• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""Unit tests for memory-based file-like objects.
2StringIO -- for unicode strings
3BytesIO -- for bytes
4"""
5
6import unittest
7from test import support
8
9import io
10import _pyio as pyio
11import pickle
12import sys
13
14class IntLike:
15    def __init__(self, num):
16        self._num = num
17    def __index__(self):
18        return self._num
19    __int__ = __index__
20
21class MemorySeekTestMixin:
22
23    def testInit(self):
24        buf = self.buftype("1234567890")
25        bytesIo = self.ioclass(buf)
26
27    def testRead(self):
28        buf = self.buftype("1234567890")
29        bytesIo = self.ioclass(buf)
30
31        self.assertEqual(buf[:1], bytesIo.read(1))
32        self.assertEqual(buf[1:5], bytesIo.read(4))
33        self.assertEqual(buf[5:], bytesIo.read(900))
34        self.assertEqual(self.EOF, bytesIo.read())
35
36    def testReadNoArgs(self):
37        buf = self.buftype("1234567890")
38        bytesIo = self.ioclass(buf)
39
40        self.assertEqual(buf, bytesIo.read())
41        self.assertEqual(self.EOF, bytesIo.read())
42
43    def testSeek(self):
44        buf = self.buftype("1234567890")
45        bytesIo = self.ioclass(buf)
46
47        bytesIo.read(5)
48        bytesIo.seek(0)
49        self.assertEqual(buf, bytesIo.read())
50
51        bytesIo.seek(3)
52        self.assertEqual(buf[3:], bytesIo.read())
53        self.assertRaises(TypeError, bytesIo.seek, 0.0)
54
55    def testTell(self):
56        buf = self.buftype("1234567890")
57        bytesIo = self.ioclass(buf)
58
59        self.assertEqual(0, bytesIo.tell())
60        bytesIo.seek(5)
61        self.assertEqual(5, bytesIo.tell())
62        bytesIo.seek(10000)
63        self.assertEqual(10000, bytesIo.tell())
64
65
66class MemoryTestMixin:
67
68    def test_detach(self):
69        buf = self.ioclass()
70        self.assertRaises(self.UnsupportedOperation, buf.detach)
71
72    def write_ops(self, f, t):
73        self.assertEqual(f.write(t("blah.")), 5)
74        self.assertEqual(f.seek(0), 0)
75        self.assertEqual(f.write(t("Hello.")), 6)
76        self.assertEqual(f.tell(), 6)
77        self.assertEqual(f.seek(5), 5)
78        self.assertEqual(f.tell(), 5)
79        self.assertEqual(f.write(t(" world\n\n\n")), 9)
80        self.assertEqual(f.seek(0), 0)
81        self.assertEqual(f.write(t("h")), 1)
82        self.assertEqual(f.truncate(12), 12)
83        self.assertEqual(f.tell(), 1)
84
85    def test_write(self):
86        buf = self.buftype("hello world\n")
87        memio = self.ioclass(buf)
88
89        self.write_ops(memio, self.buftype)
90        self.assertEqual(memio.getvalue(), buf)
91        memio = self.ioclass()
92        self.write_ops(memio, self.buftype)
93        self.assertEqual(memio.getvalue(), buf)
94        self.assertRaises(TypeError, memio.write, None)
95        memio.close()
96        self.assertRaises(ValueError, memio.write, self.buftype(""))
97
98    def test_writelines(self):
99        buf = self.buftype("1234567890")
100        memio = self.ioclass()
101
102        self.assertEqual(memio.writelines([buf] * 100), None)
103        self.assertEqual(memio.getvalue(), buf * 100)
104        memio.writelines([])
105        self.assertEqual(memio.getvalue(), buf * 100)
106        memio = self.ioclass()
107        self.assertRaises(TypeError, memio.writelines, [buf] + [1])
108        self.assertEqual(memio.getvalue(), buf)
109        self.assertRaises(TypeError, memio.writelines, None)
110        memio.close()
111        self.assertRaises(ValueError, memio.writelines, [])
112
113    def test_writelines_error(self):
114        memio = self.ioclass()
115        def error_gen():
116            yield self.buftype('spam')
117            raise KeyboardInterrupt
118
119        self.assertRaises(KeyboardInterrupt, memio.writelines, error_gen())
120
121    def test_truncate(self):
122        buf = self.buftype("1234567890")
123        memio = self.ioclass(buf)
124
125        self.assertRaises(ValueError, memio.truncate, -1)
126        self.assertRaises(ValueError, memio.truncate, IntLike(-1))
127        memio.seek(6)
128        self.assertEqual(memio.truncate(IntLike(8)), 8)
129        self.assertEqual(memio.getvalue(), buf[:8])
130        self.assertEqual(memio.truncate(), 6)
131        self.assertEqual(memio.getvalue(), buf[:6])
132        self.assertEqual(memio.truncate(4), 4)
133        self.assertEqual(memio.getvalue(), buf[:4])
134        self.assertEqual(memio.tell(), 6)
135        memio.seek(0, 2)
136        memio.write(buf)
137        self.assertEqual(memio.getvalue(), buf[:4] + buf)
138        pos = memio.tell()
139        self.assertEqual(memio.truncate(None), pos)
140        self.assertEqual(memio.tell(), pos)
141        self.assertRaises(TypeError, memio.truncate, '0')
142        memio.close()
143        self.assertRaises(ValueError, memio.truncate, 0)
144        self.assertRaises(ValueError, memio.truncate, IntLike(0))
145
146    def test_init(self):
147        buf = self.buftype("1234567890")
148        memio = self.ioclass(buf)
149        self.assertEqual(memio.getvalue(), buf)
150        memio = self.ioclass(None)
151        self.assertEqual(memio.getvalue(), self.EOF)
152        memio.__init__(buf * 2)
153        self.assertEqual(memio.getvalue(), buf * 2)
154        memio.__init__(buf)
155        self.assertEqual(memio.getvalue(), buf)
156        self.assertRaises(TypeError, memio.__init__, [])
157
158    def test_read(self):
159        buf = self.buftype("1234567890")
160        memio = self.ioclass(buf)
161
162        self.assertEqual(memio.read(0), self.EOF)
163        self.assertEqual(memio.read(1), buf[:1])
164        self.assertEqual(memio.read(4), buf[1:5])
165        self.assertEqual(memio.read(900), buf[5:])
166        self.assertEqual(memio.read(), self.EOF)
167        memio.seek(0)
168        self.assertEqual(memio.read(IntLike(0)), self.EOF)
169        self.assertEqual(memio.read(IntLike(1)), buf[:1])
170        self.assertEqual(memio.read(IntLike(4)), buf[1:5])
171        self.assertEqual(memio.read(IntLike(900)), buf[5:])
172        memio.seek(0)
173        self.assertEqual(memio.read(), buf)
174        self.assertEqual(memio.read(), self.EOF)
175        self.assertEqual(memio.tell(), 10)
176        memio.seek(0)
177        self.assertEqual(memio.read(-1), buf)
178        memio.seek(0)
179        self.assertEqual(memio.read(IntLike(-1)), buf)
180        memio.seek(0)
181        self.assertEqual(type(memio.read()), type(buf))
182        memio.seek(100)
183        self.assertEqual(type(memio.read()), type(buf))
184        memio.seek(0)
185        self.assertEqual(memio.read(None), buf)
186        self.assertRaises(TypeError, memio.read, '')
187        memio.seek(len(buf) + 1)
188        self.assertEqual(memio.read(1), self.EOF)
189        memio.seek(len(buf) + 1)
190        self.assertEqual(memio.read(IntLike(1)), self.EOF)
191        memio.seek(len(buf) + 1)
192        self.assertEqual(memio.read(), self.EOF)
193        memio.close()
194        self.assertRaises(ValueError, memio.read)
195
196    def test_readline(self):
197        buf = self.buftype("1234567890\n")
198        memio = self.ioclass(buf * 2)
199
200        self.assertEqual(memio.readline(0), self.EOF)
201        self.assertEqual(memio.readline(IntLike(0)), self.EOF)
202        self.assertEqual(memio.readline(), buf)
203        self.assertEqual(memio.readline(), buf)
204        self.assertEqual(memio.readline(), self.EOF)
205        memio.seek(0)
206        self.assertEqual(memio.readline(5), buf[:5])
207        self.assertEqual(memio.readline(5), buf[5:10])
208        self.assertEqual(memio.readline(5), buf[10:15])
209        memio.seek(0)
210        self.assertEqual(memio.readline(IntLike(5)), buf[:5])
211        self.assertEqual(memio.readline(IntLike(5)), buf[5:10])
212        self.assertEqual(memio.readline(IntLike(5)), buf[10:15])
213        memio.seek(0)
214        self.assertEqual(memio.readline(-1), buf)
215        memio.seek(0)
216        self.assertEqual(memio.readline(IntLike(-1)), buf)
217        memio.seek(0)
218        self.assertEqual(memio.readline(0), self.EOF)
219        self.assertEqual(memio.readline(IntLike(0)), self.EOF)
220        # Issue #24989: Buffer overread
221        memio.seek(len(buf) * 2 + 1)
222        self.assertEqual(memio.readline(), self.EOF)
223
224        buf = self.buftype("1234567890\n")
225        memio = self.ioclass((buf * 3)[:-1])
226        self.assertEqual(memio.readline(), buf)
227        self.assertEqual(memio.readline(), buf)
228        self.assertEqual(memio.readline(), buf[:-1])
229        self.assertEqual(memio.readline(), self.EOF)
230        memio.seek(0)
231        self.assertEqual(type(memio.readline()), type(buf))
232        self.assertEqual(memio.readline(), buf)
233        self.assertRaises(TypeError, memio.readline, '')
234        memio.close()
235        self.assertRaises(ValueError,  memio.readline)
236
237    def test_readlines(self):
238        buf = self.buftype("1234567890\n")
239        memio = self.ioclass(buf * 10)
240
241        self.assertEqual(memio.readlines(), [buf] * 10)
242        memio.seek(5)
243        self.assertEqual(memio.readlines(), [buf[5:]] + [buf] * 9)
244        memio.seek(0)
245        self.assertEqual(memio.readlines(15), [buf] * 2)
246        memio.seek(0)
247        self.assertEqual(memio.readlines(-1), [buf] * 10)
248        memio.seek(0)
249        self.assertEqual(memio.readlines(0), [buf] * 10)
250        memio.seek(0)
251        self.assertEqual(type(memio.readlines()[0]), type(buf))
252        memio.seek(0)
253        self.assertEqual(memio.readlines(None), [buf] * 10)
254        self.assertRaises(TypeError, memio.readlines, '')
255        # Issue #24989: Buffer overread
256        memio.seek(len(buf) * 10 + 1)
257        self.assertEqual(memio.readlines(), [])
258        memio.close()
259        self.assertRaises(ValueError, memio.readlines)
260
261    def test_iterator(self):
262        buf = self.buftype("1234567890\n")
263        memio = self.ioclass(buf * 10)
264
265        self.assertEqual(iter(memio), memio)
266        self.assertTrue(hasattr(memio, '__iter__'))
267        self.assertTrue(hasattr(memio, '__next__'))
268        i = 0
269        for line in memio:
270            self.assertEqual(line, buf)
271            i += 1
272        self.assertEqual(i, 10)
273        memio.seek(0)
274        i = 0
275        for line in memio:
276            self.assertEqual(line, buf)
277            i += 1
278        self.assertEqual(i, 10)
279        # Issue #24989: Buffer overread
280        memio.seek(len(buf) * 10 + 1)
281        self.assertEqual(list(memio), [])
282        memio = self.ioclass(buf * 2)
283        memio.close()
284        self.assertRaises(ValueError, memio.__next__)
285
286    def test_getvalue(self):
287        buf = self.buftype("1234567890")
288        memio = self.ioclass(buf)
289
290        self.assertEqual(memio.getvalue(), buf)
291        memio.read()
292        self.assertEqual(memio.getvalue(), buf)
293        self.assertEqual(type(memio.getvalue()), type(buf))
294        memio = self.ioclass(buf * 1000)
295        self.assertEqual(memio.getvalue()[-3:], self.buftype("890"))
296        memio = self.ioclass(buf)
297        memio.close()
298        self.assertRaises(ValueError, memio.getvalue)
299
300    def test_seek(self):
301        buf = self.buftype("1234567890")
302        memio = self.ioclass(buf)
303
304        memio.read(5)
305        self.assertRaises(ValueError, memio.seek, -1)
306        self.assertRaises(ValueError, memio.seek, 1, -1)
307        self.assertRaises(ValueError, memio.seek, 1, 3)
308        self.assertEqual(memio.seek(0), 0)
309        self.assertEqual(memio.seek(0, 0), 0)
310        self.assertEqual(memio.read(), buf)
311        self.assertEqual(memio.seek(3), 3)
312        self.assertEqual(memio.seek(0, 1), 3)
313        self.assertEqual(memio.read(), buf[3:])
314        self.assertEqual(memio.seek(len(buf)), len(buf))
315        self.assertEqual(memio.read(), self.EOF)
316        memio.seek(len(buf) + 1)
317        self.assertEqual(memio.read(), self.EOF)
318        self.assertEqual(memio.seek(0, 2), len(buf))
319        self.assertEqual(memio.read(), self.EOF)
320        memio.close()
321        self.assertRaises(ValueError, memio.seek, 0)
322
323    def test_overseek(self):
324        buf = self.buftype("1234567890")
325        memio = self.ioclass(buf)
326
327        self.assertEqual(memio.seek(len(buf) + 1), 11)
328        self.assertEqual(memio.read(), self.EOF)
329        self.assertEqual(memio.tell(), 11)
330        self.assertEqual(memio.getvalue(), buf)
331        memio.write(self.EOF)
332        self.assertEqual(memio.getvalue(), buf)
333        memio.write(buf)
334        self.assertEqual(memio.getvalue(), buf + self.buftype('\0') + buf)
335
336    def test_tell(self):
337        buf = self.buftype("1234567890")
338        memio = self.ioclass(buf)
339
340        self.assertEqual(memio.tell(), 0)
341        memio.seek(5)
342        self.assertEqual(memio.tell(), 5)
343        memio.seek(10000)
344        self.assertEqual(memio.tell(), 10000)
345        memio.close()
346        self.assertRaises(ValueError, memio.tell)
347
348    def test_flush(self):
349        buf = self.buftype("1234567890")
350        memio = self.ioclass(buf)
351
352        self.assertEqual(memio.flush(), None)
353
354    def test_flags(self):
355        memio = self.ioclass()
356
357        self.assertEqual(memio.writable(), True)
358        self.assertEqual(memio.readable(), True)
359        self.assertEqual(memio.seekable(), True)
360        self.assertEqual(memio.isatty(), False)
361        self.assertEqual(memio.closed, False)
362        memio.close()
363        self.assertRaises(ValueError, memio.writable)
364        self.assertRaises(ValueError, memio.readable)
365        self.assertRaises(ValueError, memio.seekable)
366        self.assertRaises(ValueError, memio.isatty)
367        self.assertEqual(memio.closed, True)
368
369    def test_subclassing(self):
370        buf = self.buftype("1234567890")
371        def test1():
372            class MemIO(self.ioclass):
373                pass
374            m = MemIO(buf)
375            return m.getvalue()
376        def test2():
377            class MemIO(self.ioclass):
378                def __init__(me, a, b):
379                    self.ioclass.__init__(me, a)
380            m = MemIO(buf, None)
381            return m.getvalue()
382        self.assertEqual(test1(), buf)
383        self.assertEqual(test2(), buf)
384
385    def test_instance_dict_leak(self):
386        # Test case for issue #6242.
387        # This will be caught by regrtest.py -R if this leak.
388        for _ in range(100):
389            memio = self.ioclass()
390            memio.foo = 1
391
392    def test_pickling(self):
393        buf = self.buftype("1234567890")
394        memio = self.ioclass(buf)
395        memio.foo = 42
396        memio.seek(2)
397
398        class PickleTestMemIO(self.ioclass):
399            def __init__(me, initvalue, foo):
400                self.ioclass.__init__(me, initvalue)
401                me.foo = foo
402            # __getnewargs__ is undefined on purpose. This checks that PEP 307
403            # is used to provide pickling support.
404
405        # Pickle expects the class to be on the module level. Here we use a
406        # little hack to allow the PickleTestMemIO class to derive from
407        # self.ioclass without having to define all combinations explicitly on
408        # the module-level.
409        import __main__
410        PickleTestMemIO.__module__ = '__main__'
411        PickleTestMemIO.__qualname__ = PickleTestMemIO.__name__
412        __main__.PickleTestMemIO = PickleTestMemIO
413        submemio = PickleTestMemIO(buf, 80)
414        submemio.seek(2)
415
416        # We only support pickle protocol 2 and onward since we use extended
417        # __reduce__ API of PEP 307 to provide pickling support.
418        for proto in range(2, pickle.HIGHEST_PROTOCOL + 1):
419            for obj in (memio, submemio):
420                obj2 = pickle.loads(pickle.dumps(obj, protocol=proto))
421                self.assertEqual(obj.getvalue(), obj2.getvalue())
422                self.assertEqual(obj.__class__, obj2.__class__)
423                self.assertEqual(obj.foo, obj2.foo)
424                self.assertEqual(obj.tell(), obj2.tell())
425                obj2.close()
426                self.assertRaises(ValueError, pickle.dumps, obj2, proto)
427        del __main__.PickleTestMemIO
428
429
430class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase):
431    # Test _pyio.BytesIO; class also inherited for testing C implementation
432
433    UnsupportedOperation = pyio.UnsupportedOperation
434
435    @staticmethod
436    def buftype(s):
437        return s.encode("ascii")
438    ioclass = pyio.BytesIO
439    EOF = b""
440
441    def test_getbuffer(self):
442        memio = self.ioclass(b"1234567890")
443        buf = memio.getbuffer()
444        self.assertEqual(bytes(buf), b"1234567890")
445        memio.seek(5)
446        buf = memio.getbuffer()
447        self.assertEqual(bytes(buf), b"1234567890")
448        # Trying to change the size of the BytesIO while a buffer is exported
449        # raises a BufferError.
450        self.assertRaises(BufferError, memio.write, b'x' * 100)
451        self.assertRaises(BufferError, memio.truncate)
452        self.assertRaises(BufferError, memio.close)
453        self.assertFalse(memio.closed)
454        # Mutating the buffer updates the BytesIO
455        buf[3:6] = b"abc"
456        self.assertEqual(bytes(buf), b"123abc7890")
457        self.assertEqual(memio.getvalue(), b"123abc7890")
458        # After the buffer gets released, we can resize and close the BytesIO
459        # again
460        del buf
461        support.gc_collect()
462        memio.truncate()
463        memio.close()
464        self.assertRaises(ValueError, memio.getbuffer)
465
466    def test_read1(self):
467        buf = self.buftype("1234567890")
468        self.assertEqual(self.ioclass(buf).read1(), buf)
469        self.assertEqual(self.ioclass(buf).read1(-1), buf)
470
471    def test_readinto(self):
472        buf = self.buftype("1234567890")
473        memio = self.ioclass(buf)
474
475        b = bytearray(b"hello")
476        self.assertEqual(memio.readinto(b), 5)
477        self.assertEqual(b, b"12345")
478        self.assertEqual(memio.readinto(b), 5)
479        self.assertEqual(b, b"67890")
480        self.assertEqual(memio.readinto(b), 0)
481        self.assertEqual(b, b"67890")
482        b = bytearray(b"hello world")
483        memio.seek(0)
484        self.assertEqual(memio.readinto(b), 10)
485        self.assertEqual(b, b"1234567890d")
486        b = bytearray(b"")
487        memio.seek(0)
488        self.assertEqual(memio.readinto(b), 0)
489        self.assertEqual(b, b"")
490        self.assertRaises(TypeError, memio.readinto, '')
491        import array
492        a = array.array('b', b"hello world")
493        memio = self.ioclass(buf)
494        memio.readinto(a)
495        self.assertEqual(a.tobytes(), b"1234567890d")
496        memio.close()
497        self.assertRaises(ValueError, memio.readinto, b)
498        memio = self.ioclass(b"123")
499        b = bytearray()
500        memio.seek(42)
501        memio.readinto(b)
502        self.assertEqual(b, b"")
503
504    def test_relative_seek(self):
505        buf = self.buftype("1234567890")
506        memio = self.ioclass(buf)
507
508        self.assertEqual(memio.seek(-1, 1), 0)
509        self.assertEqual(memio.seek(3, 1), 3)
510        self.assertEqual(memio.seek(-4, 1), 0)
511        self.assertEqual(memio.seek(-1, 2), 9)
512        self.assertEqual(memio.seek(1, 1), 10)
513        self.assertEqual(memio.seek(1, 2), 11)
514        memio.seek(-3, 2)
515        self.assertEqual(memio.read(), buf[-3:])
516        memio.seek(0)
517        memio.seek(1, 1)
518        self.assertEqual(memio.read(), buf[1:])
519
520    def test_unicode(self):
521        memio = self.ioclass()
522
523        self.assertRaises(TypeError, self.ioclass, "1234567890")
524        self.assertRaises(TypeError, memio.write, "1234567890")
525        self.assertRaises(TypeError, memio.writelines, ["1234567890"])
526
527    def test_bytes_array(self):
528        buf = b"1234567890"
529        import array
530        a = array.array('b', list(buf))
531        memio = self.ioclass(a)
532        self.assertEqual(memio.getvalue(), buf)
533        self.assertEqual(memio.write(a), 10)
534        self.assertEqual(memio.getvalue(), buf)
535
536    def test_issue5449(self):
537        buf = self.buftype("1234567890")
538        self.ioclass(initial_bytes=buf)
539        self.assertRaises(TypeError, self.ioclass, buf, foo=None)
540
541
542class TextIOTestMixin:
543
544    def test_newlines_property(self):
545        memio = self.ioclass(newline=None)
546        # The C StringIO decodes newlines in write() calls, but the Python
547        # implementation only does when reading.  This function forces them to
548        # be decoded for testing.
549        def force_decode():
550            memio.seek(0)
551            memio.read()
552        self.assertEqual(memio.newlines, None)
553        memio.write("a\n")
554        force_decode()
555        self.assertEqual(memio.newlines, "\n")
556        memio.write("b\r\n")
557        force_decode()
558        self.assertEqual(memio.newlines, ("\n", "\r\n"))
559        memio.write("c\rd")
560        force_decode()
561        self.assertEqual(memio.newlines, ("\r", "\n", "\r\n"))
562
563    def test_relative_seek(self):
564        memio = self.ioclass()
565
566        self.assertRaises(OSError, memio.seek, -1, 1)
567        self.assertRaises(OSError, memio.seek, 3, 1)
568        self.assertRaises(OSError, memio.seek, -3, 1)
569        self.assertRaises(OSError, memio.seek, -1, 2)
570        self.assertRaises(OSError, memio.seek, 1, 1)
571        self.assertRaises(OSError, memio.seek, 1, 2)
572
573    def test_textio_properties(self):
574        memio = self.ioclass()
575
576        # These are just dummy values but we nevertheless check them for fear
577        # of unexpected breakage.
578        self.assertIsNone(memio.encoding)
579        self.assertIsNone(memio.errors)
580        self.assertFalse(memio.line_buffering)
581
582    def test_newline_default(self):
583        memio = self.ioclass("a\nb\r\nc\rd")
584        self.assertEqual(list(memio), ["a\n", "b\r\n", "c\rd"])
585        self.assertEqual(memio.getvalue(), "a\nb\r\nc\rd")
586
587        memio = self.ioclass()
588        self.assertEqual(memio.write("a\nb\r\nc\rd"), 8)
589        memio.seek(0)
590        self.assertEqual(list(memio), ["a\n", "b\r\n", "c\rd"])
591        self.assertEqual(memio.getvalue(), "a\nb\r\nc\rd")
592
593    def test_newline_none(self):
594        # newline=None
595        memio = self.ioclass("a\nb\r\nc\rd", newline=None)
596        self.assertEqual(list(memio), ["a\n", "b\n", "c\n", "d"])
597        memio.seek(0)
598        self.assertEqual(memio.read(1), "a")
599        self.assertEqual(memio.read(2), "\nb")
600        self.assertEqual(memio.read(2), "\nc")
601        self.assertEqual(memio.read(1), "\n")
602        self.assertEqual(memio.getvalue(), "a\nb\nc\nd")
603
604        memio = self.ioclass(newline=None)
605        self.assertEqual(2, memio.write("a\n"))
606        self.assertEqual(3, memio.write("b\r\n"))
607        self.assertEqual(3, memio.write("c\rd"))
608        memio.seek(0)
609        self.assertEqual(memio.read(), "a\nb\nc\nd")
610        self.assertEqual(memio.getvalue(), "a\nb\nc\nd")
611
612        memio = self.ioclass("a\r\nb", newline=None)
613        self.assertEqual(memio.read(3), "a\nb")
614
615    def test_newline_empty(self):
616        # newline=""
617        memio = self.ioclass("a\nb\r\nc\rd", newline="")
618        self.assertEqual(list(memio), ["a\n", "b\r\n", "c\r", "d"])
619        memio.seek(0)
620        self.assertEqual(memio.read(4), "a\nb\r")
621        self.assertEqual(memio.read(2), "\nc")
622        self.assertEqual(memio.read(1), "\r")
623        self.assertEqual(memio.getvalue(), "a\nb\r\nc\rd")
624
625        memio = self.ioclass(newline="")
626        self.assertEqual(2, memio.write("a\n"))
627        self.assertEqual(2, memio.write("b\r"))
628        self.assertEqual(2, memio.write("\nc"))
629        self.assertEqual(2, memio.write("\rd"))
630        memio.seek(0)
631        self.assertEqual(list(memio), ["a\n", "b\r\n", "c\r", "d"])
632        self.assertEqual(memio.getvalue(), "a\nb\r\nc\rd")
633
634    def test_newline_lf(self):
635        # newline="\n"
636        memio = self.ioclass("a\nb\r\nc\rd", newline="\n")
637        self.assertEqual(list(memio), ["a\n", "b\r\n", "c\rd"])
638        self.assertEqual(memio.getvalue(), "a\nb\r\nc\rd")
639
640        memio = self.ioclass(newline="\n")
641        self.assertEqual(memio.write("a\nb\r\nc\rd"), 8)
642        memio.seek(0)
643        self.assertEqual(list(memio), ["a\n", "b\r\n", "c\rd"])
644        self.assertEqual(memio.getvalue(), "a\nb\r\nc\rd")
645
646    def test_newline_cr(self):
647        # newline="\r"
648        memio = self.ioclass("a\nb\r\nc\rd", newline="\r")
649        self.assertEqual(memio.read(), "a\rb\r\rc\rd")
650        memio.seek(0)
651        self.assertEqual(list(memio), ["a\r", "b\r", "\r", "c\r", "d"])
652        self.assertEqual(memio.getvalue(), "a\rb\r\rc\rd")
653
654        memio = self.ioclass(newline="\r")
655        self.assertEqual(memio.write("a\nb\r\nc\rd"), 8)
656        memio.seek(0)
657        self.assertEqual(list(memio), ["a\r", "b\r", "\r", "c\r", "d"])
658        memio.seek(0)
659        self.assertEqual(memio.readlines(), ["a\r", "b\r", "\r", "c\r", "d"])
660        self.assertEqual(memio.getvalue(), "a\rb\r\rc\rd")
661
662    def test_newline_crlf(self):
663        # newline="\r\n"
664        memio = self.ioclass("a\nb\r\nc\rd", newline="\r\n")
665        self.assertEqual(memio.read(), "a\r\nb\r\r\nc\rd")
666        memio.seek(0)
667        self.assertEqual(list(memio), ["a\r\n", "b\r\r\n", "c\rd"])
668        memio.seek(0)
669        self.assertEqual(memio.readlines(), ["a\r\n", "b\r\r\n", "c\rd"])
670        self.assertEqual(memio.getvalue(), "a\r\nb\r\r\nc\rd")
671
672        memio = self.ioclass(newline="\r\n")
673        self.assertEqual(memio.write("a\nb\r\nc\rd"), 8)
674        memio.seek(0)
675        self.assertEqual(list(memio), ["a\r\n", "b\r\r\n", "c\rd"])
676        self.assertEqual(memio.getvalue(), "a\r\nb\r\r\nc\rd")
677
678    def test_issue5265(self):
679        # StringIO can duplicate newlines in universal newlines mode
680        memio = self.ioclass("a\r\nb\r\n", newline=None)
681        self.assertEqual(memio.read(5), "a\nb\n")
682        self.assertEqual(memio.getvalue(), "a\nb\n")
683
684    def test_newline_argument(self):
685        self.assertRaises(TypeError, self.ioclass, newline=b"\n")
686        self.assertRaises(ValueError, self.ioclass, newline="error")
687        # These should not raise an error
688        for newline in (None, "", "\n", "\r", "\r\n"):
689            self.ioclass(newline=newline)
690
691
692class PyStringIOTest(MemoryTestMixin, MemorySeekTestMixin,
693                     TextIOTestMixin, unittest.TestCase):
694    buftype = str
695    ioclass = pyio.StringIO
696    UnsupportedOperation = pyio.UnsupportedOperation
697    EOF = ""
698
699    def test_lone_surrogates(self):
700        # Issue #20424
701        memio = self.ioclass('\ud800')
702        self.assertEqual(memio.read(), '\ud800')
703
704        memio = self.ioclass()
705        memio.write('\ud800')
706        self.assertEqual(memio.getvalue(), '\ud800')
707
708
709class PyStringIOPickleTest(TextIOTestMixin, unittest.TestCase):
710    """Test if pickle restores properly the internal state of StringIO.
711    """
712    buftype = str
713    UnsupportedOperation = pyio.UnsupportedOperation
714    EOF = ""
715
716    class ioclass(pyio.StringIO):
717        def __new__(cls, *args, **kwargs):
718            return pickle.loads(pickle.dumps(pyio.StringIO(*args, **kwargs)))
719        def __init__(self, *args, **kwargs):
720            pass
721
722
723class CBytesIOTest(PyBytesIOTest):
724    ioclass = io.BytesIO
725    UnsupportedOperation = io.UnsupportedOperation
726
727    def test_getstate(self):
728        memio = self.ioclass()
729        state = memio.__getstate__()
730        self.assertEqual(len(state), 3)
731        bytearray(state[0]) # Check if state[0] supports the buffer interface.
732        self.assertIsInstance(state[1], int)
733        if state[2] is not None:
734            self.assertIsInstance(state[2], dict)
735        memio.close()
736        self.assertRaises(ValueError, memio.__getstate__)
737
738    def test_setstate(self):
739        # This checks whether __setstate__ does proper input validation.
740        memio = self.ioclass()
741        memio.__setstate__((b"no error", 0, None))
742        memio.__setstate__((bytearray(b"no error"), 0, None))
743        memio.__setstate__((b"no error", 0, {'spam': 3}))
744        self.assertRaises(ValueError, memio.__setstate__, (b"", -1, None))
745        self.assertRaises(TypeError, memio.__setstate__, ("unicode", 0, None))
746        self.assertRaises(TypeError, memio.__setstate__, (b"", 0.0, None))
747        self.assertRaises(TypeError, memio.__setstate__, (b"", 0, 0))
748        self.assertRaises(TypeError, memio.__setstate__, (b"len-test", 0))
749        self.assertRaises(TypeError, memio.__setstate__)
750        self.assertRaises(TypeError, memio.__setstate__, 0)
751        memio.close()
752        self.assertRaises(ValueError, memio.__setstate__, (b"closed", 0, None))
753
754    check_sizeof = support.check_sizeof
755
756    @support.cpython_only
757    def test_sizeof(self):
758        basesize = support.calcobjsize('P2n2Pn')
759        check = self.check_sizeof
760        self.assertEqual(object.__sizeof__(io.BytesIO()), basesize)
761        check(io.BytesIO(), basesize )
762        n = 1000  # use a variable to prevent constant folding
763        check(io.BytesIO(b'a' * n), basesize + sys.getsizeof(b'a' * n))
764
765    # Various tests of copy-on-write behaviour for BytesIO.
766
767    def _test_cow_mutation(self, mutation):
768        # Common code for all BytesIO copy-on-write mutation tests.
769        imm = b' ' * 1024
770        old_rc = sys.getrefcount(imm)
771        memio = self.ioclass(imm)
772        self.assertEqual(sys.getrefcount(imm), old_rc + 1)
773        mutation(memio)
774        self.assertEqual(sys.getrefcount(imm), old_rc)
775
776    @support.cpython_only
777    def test_cow_truncate(self):
778        # Ensure truncate causes a copy.
779        def mutation(memio):
780            memio.truncate(1)
781        self._test_cow_mutation(mutation)
782
783    @support.cpython_only
784    def test_cow_write(self):
785        # Ensure write that would not cause a resize still results in a copy.
786        def mutation(memio):
787            memio.seek(0)
788            memio.write(b'foo')
789        self._test_cow_mutation(mutation)
790
791    @support.cpython_only
792    def test_cow_setstate(self):
793        # __setstate__ should cause buffer to be released.
794        memio = self.ioclass(b'foooooo')
795        state = memio.__getstate__()
796        def mutation(memio):
797            memio.__setstate__(state)
798        self._test_cow_mutation(mutation)
799
800    @support.cpython_only
801    def test_cow_mutable(self):
802        # BytesIO should accept only Bytes for copy-on-write sharing, since
803        # arbitrary buffer-exporting objects like bytearray() aren't guaranteed
804        # to be immutable.
805        ba = bytearray(1024)
806        old_rc = sys.getrefcount(ba)
807        memio = self.ioclass(ba)
808        self.assertEqual(sys.getrefcount(ba), old_rc)
809
810class CStringIOTest(PyStringIOTest):
811    ioclass = io.StringIO
812    UnsupportedOperation = io.UnsupportedOperation
813
814    # XXX: For the Python version of io.StringIO, this is highly
815    # dependent on the encoding used for the underlying buffer.
816    def test_widechar(self):
817        buf = self.buftype("\U0002030a\U00020347")
818        memio = self.ioclass(buf)
819
820        self.assertEqual(memio.getvalue(), buf)
821        self.assertEqual(memio.write(buf), len(buf))
822        self.assertEqual(memio.tell(), len(buf))
823        self.assertEqual(memio.getvalue(), buf)
824        self.assertEqual(memio.write(buf), len(buf))
825        self.assertEqual(memio.tell(), len(buf) * 2)
826        self.assertEqual(memio.getvalue(), buf + buf)
827
828    def test_getstate(self):
829        memio = self.ioclass()
830        state = memio.__getstate__()
831        self.assertEqual(len(state), 4)
832        self.assertIsInstance(state[0], str)
833        self.assertIsInstance(state[1], str)
834        self.assertIsInstance(state[2], int)
835        if state[3] is not None:
836            self.assertIsInstance(state[3], dict)
837        memio.close()
838        self.assertRaises(ValueError, memio.__getstate__)
839
840    def test_setstate(self):
841        # This checks whether __setstate__ does proper input validation.
842        memio = self.ioclass()
843        memio.__setstate__(("no error", "\n", 0, None))
844        memio.__setstate__(("no error", "", 0, {'spam': 3}))
845        self.assertRaises(ValueError, memio.__setstate__, ("", "f", 0, None))
846        self.assertRaises(ValueError, memio.__setstate__, ("", "", -1, None))
847        self.assertRaises(TypeError, memio.__setstate__, (b"", "", 0, None))
848        self.assertRaises(TypeError, memio.__setstate__, ("", b"", 0, None))
849        self.assertRaises(TypeError, memio.__setstate__, ("", "", 0.0, None))
850        self.assertRaises(TypeError, memio.__setstate__, ("", "", 0, 0))
851        self.assertRaises(TypeError, memio.__setstate__, ("len-test", 0))
852        self.assertRaises(TypeError, memio.__setstate__)
853        self.assertRaises(TypeError, memio.__setstate__, 0)
854        memio.close()
855        self.assertRaises(ValueError, memio.__setstate__, ("closed", "", 0, None))
856
857
858class CStringIOPickleTest(PyStringIOPickleTest):
859    UnsupportedOperation = io.UnsupportedOperation
860
861    class ioclass(io.StringIO):
862        def __new__(cls, *args, **kwargs):
863            return pickle.loads(pickle.dumps(io.StringIO(*args, **kwargs)))
864        def __init__(self, *args, **kwargs):
865            pass
866
867
868if __name__ == '__main__':
869    unittest.main()
870