blob: 4604caf0d10238951441aad268a60f0e0be78e8c [file] [log] [blame]
Alexandre Vassalotti77250f42008-05-06 19:48:38 +00001"""Unit tests for memory-based file-like objects.
2StringIO -- for unicode strings
3BytesIO -- for bytes
4"""
5
6import unittest
7from test import test_support
8
9import io
Alexandre Vassalotti1bfe9dc82008-05-07 01:44:31 +000010import sys
Alexandre Vassalotti77250f42008-05-06 19:48:38 +000011
12try:
13 import _bytesio
14 has_c_implementation = True
15except ImportError:
16 has_c_implementation = False
17
18
19class MemoryTestMixin:
20
21 def write_ops(self, f, t):
22 self.assertEqual(f.write(t("blah.")), 5)
23 self.assertEqual(f.seek(0), 0)
24 self.assertEqual(f.write(t("Hello.")), 6)
25 self.assertEqual(f.tell(), 6)
26 self.assertEqual(f.seek(5), 5)
27 self.assertEqual(f.tell(), 5)
28 self.assertEqual(f.write(t(" world\n\n\n")), 9)
29 self.assertEqual(f.seek(0), 0)
30 self.assertEqual(f.write(t("h")), 1)
31 self.assertEqual(f.truncate(12), 12)
32 self.assertEqual(f.tell(), 12)
33
34 def test_write(self):
35 buf = self.buftype("hello world\n")
36 memio = self.ioclass(buf)
37
38 self.write_ops(memio, self.buftype)
39 self.assertEqual(memio.getvalue(), buf)
40 memio = self.ioclass()
41 self.write_ops(memio, self.buftype)
42 self.assertEqual(memio.getvalue(), buf)
43 self.assertRaises(TypeError, memio.write, None)
44 memio.close()
45 self.assertRaises(ValueError, memio.write, self.buftype(""))
46
47 def test_writelines(self):
48 buf = self.buftype("1234567890")
49 memio = self.ioclass()
50
51 self.assertEqual(memio.writelines([buf] * 100), None)
52 self.assertEqual(memio.getvalue(), buf * 100)
53 memio.writelines([])
54 self.assertEqual(memio.getvalue(), buf * 100)
55 memio = self.ioclass()
56 self.assertRaises(TypeError, memio.writelines, [buf] + [1])
57 self.assertEqual(memio.getvalue(), buf)
58 self.assertRaises(TypeError, memio.writelines, None)
59 memio.close()
60 self.assertRaises(ValueError, memio.writelines, [])
61
62 def test_writelines_error(self):
63 memio = self.ioclass()
64 def error_gen():
65 yield self.buftype('spam')
66 raise KeyboardInterrupt
67
68 self.assertRaises(KeyboardInterrupt, memio.writelines, error_gen())
69
70 def test_truncate(self):
71 buf = self.buftype("1234567890")
72 memio = self.ioclass(buf)
73
74 self.assertRaises(ValueError, memio.truncate, -1)
75 memio.seek(6)
76 self.assertEqual(memio.truncate(), 6)
77 self.assertEqual(memio.getvalue(), buf[:6])
78 self.assertEqual(memio.truncate(4), 4)
79 self.assertEqual(memio.getvalue(), buf[:4])
80 self.assertEqual(memio.tell(), 4)
81 memio.write(buf)
82 self.assertEqual(memio.getvalue(), buf[:4] + buf)
83 pos = memio.tell()
84 self.assertEqual(memio.truncate(None), pos)
85 self.assertEqual(memio.tell(), pos)
86 self.assertRaises(TypeError, memio.truncate, '0')
87 memio.close()
88 self.assertRaises(ValueError, memio.truncate, 0)
89
90 def test_init(self):
91 buf = self.buftype("1234567890")
92 memio = self.ioclass(buf)
93 self.assertEqual(memio.getvalue(), buf)
94 memio = self.ioclass(None)
95 self.assertEqual(memio.getvalue(), self.EOF)
96 memio.__init__(buf * 2)
97 self.assertEqual(memio.getvalue(), buf * 2)
98 memio.__init__(buf)
99 self.assertEqual(memio.getvalue(), buf)
100
101 def test_read(self):
102 buf = self.buftype("1234567890")
103 memio = self.ioclass(buf)
104
105 self.assertEqual(memio.read(0), self.EOF)
106 self.assertEqual(memio.read(1), buf[:1])
107 self.assertEqual(memio.read(4), buf[1:5])
108 self.assertEqual(memio.read(900), buf[5:])
109 self.assertEqual(memio.read(), self.EOF)
110 memio.seek(0)
111 self.assertEqual(memio.read(), buf)
112 self.assertEqual(memio.read(), self.EOF)
113 self.assertEqual(memio.tell(), 10)
114 memio.seek(0)
115 self.assertEqual(memio.read(-1), buf)
116 memio.seek(0)
Alexandre Vassalotti5da31eb2008-05-06 20:30:41 +0000117 self.assertEqual(type(memio.read()), type(buf))
Alexandre Vassalotti4833b3c2008-05-06 23:47:23 +0000118 memio.seek(100)
119 self.assertEqual(type(memio.read()), type(buf))
Alexandre Vassalotti5da31eb2008-05-06 20:30:41 +0000120 memio.seek(0)
Alexandre Vassalotti77250f42008-05-06 19:48:38 +0000121 self.assertEqual(memio.read(None), buf)
122 self.assertRaises(TypeError, memio.read, '')
123 memio.close()
124 self.assertRaises(ValueError, memio.read)
125
126 def test_readline(self):
127 buf = self.buftype("1234567890\n")
128 memio = self.ioclass(buf * 2)
129
130 self.assertEqual(memio.readline(0), self.EOF)
131 self.assertEqual(memio.readline(), buf)
132 self.assertEqual(memio.readline(), buf)
133 self.assertEqual(memio.readline(), self.EOF)
134 memio.seek(0)
135 self.assertEqual(memio.readline(5), buf[:5])
136 self.assertEqual(memio.readline(5), buf[5:10])
137 self.assertEqual(memio.readline(5), buf[10:15])
138 memio.seek(0)
139 self.assertEqual(memio.readline(-1), buf)
140 memio.seek(0)
141 self.assertEqual(memio.readline(0), self.EOF)
142
143 buf = self.buftype("1234567890\n")
144 memio = self.ioclass((buf * 3)[:-1])
145 self.assertEqual(memio.readline(), buf)
146 self.assertEqual(memio.readline(), buf)
147 self.assertEqual(memio.readline(), buf[:-1])
148 self.assertEqual(memio.readline(), self.EOF)
149 memio.seek(0)
Alexandre Vassalotti5da31eb2008-05-06 20:30:41 +0000150 self.assertEqual(type(memio.readline()), type(buf))
Alexandre Vassalotti77250f42008-05-06 19:48:38 +0000151 self.assertEqual(memio.readline(None), buf)
152 self.assertRaises(TypeError, memio.readline, '')
153 memio.close()
154 self.assertRaises(ValueError, memio.readline)
155
156 def test_readlines(self):
157 buf = self.buftype("1234567890\n")
158 memio = self.ioclass(buf * 10)
159
160 self.assertEqual(memio.readlines(), [buf] * 10)
161 memio.seek(5)
162 self.assertEqual(memio.readlines(), [buf[5:]] + [buf] * 9)
163 memio.seek(0)
164 self.assertEqual(memio.readlines(15), [buf] * 2)
165 memio.seek(0)
166 self.assertEqual(memio.readlines(-1), [buf] * 10)
167 memio.seek(0)
168 self.assertEqual(memio.readlines(0), [buf] * 10)
169 memio.seek(0)
Alexandre Vassalotti5da31eb2008-05-06 20:30:41 +0000170 self.assertEqual(type(memio.readlines()[0]), type(buf))
171 memio.seek(0)
Alexandre Vassalotti77250f42008-05-06 19:48:38 +0000172 self.assertEqual(memio.readlines(None), [buf] * 10)
173 self.assertRaises(TypeError, memio.readlines, '')
174 memio.close()
175 self.assertRaises(ValueError, memio.readlines)
176
177 def test_iterator(self):
178 buf = self.buftype("1234567890\n")
179 memio = self.ioclass(buf * 10)
180
181 self.assertEqual(iter(memio), memio)
182 self.failUnless(hasattr(memio, '__iter__'))
183 self.failUnless(hasattr(memio, '__next__'))
184 i = 0
185 for line in memio:
186 self.assertEqual(line, buf)
187 i += 1
188 self.assertEqual(i, 10)
189 memio.seek(0)
190 i = 0
191 for line in memio:
192 self.assertEqual(line, buf)
193 i += 1
194 self.assertEqual(i, 10)
195 memio = self.ioclass(buf * 2)
196 memio.close()
197 self.assertRaises(ValueError, memio.__next__)
198
199 def test_getvalue(self):
200 buf = self.buftype("1234567890")
201 memio = self.ioclass(buf)
202
203 self.assertEqual(memio.getvalue(), buf)
204 memio.read()
205 self.assertEqual(memio.getvalue(), buf)
Alexandre Vassalotti5da31eb2008-05-06 20:30:41 +0000206 self.assertEqual(type(memio.getvalue()), type(buf))
Alexandre Vassalotti77250f42008-05-06 19:48:38 +0000207 memio = self.ioclass(buf * 1000)
208 self.assertEqual(memio.getvalue()[-3:], self.buftype("890"))
209 memio = self.ioclass(buf)
210 memio.close()
211 self.assertRaises(ValueError, memio.getvalue)
212
213 def test_seek(self):
214 buf = self.buftype("1234567890")
215 memio = self.ioclass(buf)
216
217 memio.read(5)
218 self.assertRaises(ValueError, memio.seek, -1)
219 self.assertRaises(ValueError, memio.seek, 1, -1)
220 self.assertRaises(ValueError, memio.seek, 1, 3)
221 self.assertEqual(memio.seek(0), 0)
222 self.assertEqual(memio.seek(0, 0), 0)
223 self.assertEqual(memio.read(), buf)
224 self.assertEqual(memio.seek(3), 3)
225 self.assertEqual(memio.seek(0, 1), 3)
226 self.assertEqual(memio.read(), buf[3:])
227 self.assertEqual(memio.seek(len(buf)), len(buf))
228 self.assertEqual(memio.read(), self.EOF)
229 memio.seek(len(buf) + 1)
230 self.assertEqual(memio.read(), self.EOF)
231 self.assertEqual(memio.seek(0, 2), len(buf))
232 self.assertEqual(memio.read(), self.EOF)
233 memio.close()
234 self.assertRaises(ValueError, memio.seek, 0)
235
236 def test_overseek(self):
237 buf = self.buftype("1234567890")
238 memio = self.ioclass(buf)
239
240 self.assertEqual(memio.seek(len(buf) + 1), 11)
241 self.assertEqual(memio.read(), self.EOF)
242 self.assertEqual(memio.tell(), 11)
243 self.assertEqual(memio.getvalue(), buf)
244 memio.write(self.EOF)
245 self.assertEqual(memio.getvalue(), buf)
246 memio.write(buf)
247 self.assertEqual(memio.getvalue(), buf + self.buftype('\0') + buf)
248
249 def test_tell(self):
250 buf = self.buftype("1234567890")
251 memio = self.ioclass(buf)
252
253 self.assertEqual(memio.tell(), 0)
254 memio.seek(5)
255 self.assertEqual(memio.tell(), 5)
256 memio.seek(10000)
257 self.assertEqual(memio.tell(), 10000)
258 memio.close()
259 self.assertRaises(ValueError, memio.tell)
260
261 def test_flush(self):
262 buf = self.buftype("1234567890")
263 memio = self.ioclass(buf)
264
265 self.assertEqual(memio.flush(), None)
266
267 def test_flags(self):
268 memio = self.ioclass()
269
270 self.assertEqual(memio.writable(), True)
271 self.assertEqual(memio.readable(), True)
272 self.assertEqual(memio.seekable(), True)
273 self.assertEqual(memio.isatty(), False)
274 self.assertEqual(memio.closed, False)
275 memio.close()
276 self.assertEqual(memio.writable(), True)
277 self.assertEqual(memio.readable(), True)
278 self.assertEqual(memio.seekable(), True)
279 self.assertRaises(ValueError, memio.isatty)
280 self.assertEqual(memio.closed, True)
281
282 def test_subclassing(self):
283 buf = self.buftype("1234567890")
284 def test1():
285 class MemIO(self.ioclass):
286 pass
287 m = MemIO(buf)
288 return m.getvalue()
289 def test2():
290 class MemIO(self.ioclass):
291 def __init__(me, a, b):
292 self.ioclass.__init__(me, a)
293 m = MemIO(buf, None)
294 return m.getvalue()
295 self.assertEqual(test1(), buf)
296 self.assertEqual(test2(), buf)
297
298
299class PyBytesIOTest(MemoryTestMixin, unittest.TestCase):
300 @staticmethod
301 def buftype(s):
302 return s.encode("ascii")
303 ioclass = io._BytesIO
304 EOF = b""
305
306 def test_read1(self):
307 buf = self.buftype("1234567890")
308 memio = self.ioclass(buf)
309
310 self.assertRaises(TypeError, memio.read1)
311 self.assertEqual(memio.read(), buf)
312
313 def test_readinto(self):
314 buf = self.buftype("1234567890")
315 memio = self.ioclass(buf)
316
317 b = bytearray(b"hello")
318 self.assertEqual(memio.readinto(b), 5)
319 self.assertEqual(b, b"12345")
320 self.assertEqual(memio.readinto(b), 5)
321 self.assertEqual(b, b"67890")
322 self.assertEqual(memio.readinto(b), 0)
323 self.assertEqual(b, b"67890")
324 b = bytearray(b"hello world")
325 memio.seek(0)
326 self.assertEqual(memio.readinto(b), 10)
327 self.assertEqual(b, b"1234567890d")
328 b = bytearray(b"")
329 memio.seek(0)
330 self.assertEqual(memio.readinto(b), 0)
331 self.assertEqual(b, b"")
332 self.assertRaises(TypeError, memio.readinto, '')
333 import array
334 a = array.array('b', b"hello world")
335 memio = self.ioclass(buf)
336 memio.readinto(a)
337 self.assertEqual(a.tostring(), b"1234567890d")
338 memio.close()
339 self.assertRaises(ValueError, memio.readinto, b)
340
341 def test_relative_seek(self):
342 buf = self.buftype("1234567890")
343 memio = self.ioclass(buf)
344
345 self.assertEqual(memio.seek(-1, 1), 0)
346 self.assertEqual(memio.seek(3, 1), 3)
347 self.assertEqual(memio.seek(-4, 1), 0)
348 self.assertEqual(memio.seek(-1, 2), 9)
349 self.assertEqual(memio.seek(1, 1), 10)
350 self.assertEqual(memio.seek(1, 2), 11)
351 memio.seek(-3, 2)
352 self.assertEqual(memio.read(), buf[-3:])
353 memio.seek(0)
354 memio.seek(1, 1)
355 self.assertEqual(memio.read(), buf[1:])
356
357 def test_unicode(self):
358 memio = self.ioclass()
359
360 self.assertRaises(TypeError, self.ioclass, "1234567890")
361 self.assertRaises(TypeError, memio.write, "1234567890")
362 self.assertRaises(TypeError, memio.writelines, ["1234567890"])
363
364 def test_bytes_array(self):
365 buf = b"1234567890"
366 import array
367 a = array.array('b', list(buf))
368 memio = self.ioclass(a)
369 self.assertEqual(memio.getvalue(), buf)
370 self.assertEqual(memio.write(a), 10)
371 self.assertEqual(memio.getvalue(), buf)
372
373
374class PyStringIOTest(MemoryTestMixin, unittest.TestCase):
375 buftype = str
376 ioclass = io.StringIO
377 EOF = ""
378
379 def test_relative_seek(self):
380 memio = self.ioclass()
381
382 self.assertRaises(IOError, memio.seek, -1, 1)
383 self.assertRaises(IOError, memio.seek, 3, 1)
384 self.assertRaises(IOError, memio.seek, -3, 1)
385 self.assertRaises(IOError, memio.seek, -1, 2)
386 self.assertRaises(IOError, memio.seek, 1, 1)
387 self.assertRaises(IOError, memio.seek, 1, 2)
388
389 # XXX: For the Python version of io.StringIO, this is highly
390 # dependent on the encoding used for the underlying buffer.
391 # def test_widechar(self):
392 # buf = self.buftype("\U0002030a\U00020347")
393 # memio = self.ioclass(buf)
394 #
395 # self.assertEqual(memio.getvalue(), buf)
396 # self.assertEqual(memio.write(buf), len(buf))
397 # self.assertEqual(memio.tell(), len(buf))
398 # self.assertEqual(memio.getvalue(), buf)
399 # self.assertEqual(memio.write(buf), len(buf))
400 # self.assertEqual(memio.tell(), len(buf) * 2)
401 # self.assertEqual(memio.getvalue(), buf + buf)
402
403if has_c_implementation:
404 class CBytesIOTest(PyBytesIOTest):
405 ioclass = io.BytesIO
406
Alexandre Vassalotti1bfe9dc82008-05-07 01:44:31 +0000407 def test_overflow(self):
408 buf = self.buftype("a")
409 memio = self.ioclass()
410
411 memio.seek(sys.maxsize)
412 self.assertRaises(OverflowError, memio.seek, 1, 1)
413 # Ensure that the position has not been changed
414 self.assertEqual(memio.tell(), sys.maxsize)
415 self.assertEqual(memio.write(self.EOF), 0)
416 self.assertRaises(OverflowError, memio.write, buf)
417 self.assertEqual(memio.tell(), sys.maxsize)
418
419
Alexandre Vassalotti77250f42008-05-06 19:48:38 +0000420def test_main():
421 tests = [PyBytesIOTest, PyStringIOTest]
422 if has_c_implementation:
423 tests.extend([CBytesIOTest])
424 test_support.run_unittest(*tests)
425
426if __name__ == '__main__':
427 test_main()