blob: 57e640d336416ba7f0af7338a68045c3bf99b902 [file] [log] [blame]
Antoine Pitrou47a5f482009-06-12 20:41:52 +00001# NOTE: this file tests the new `io` library backported from Python 3.x.
2# Similar tests for the builtin file object can be found in test_file2k.py.
3
Antoine Pitrou19690592009-06-12 20:14:08 +00004from __future__ import print_function
5
Martin v. Löwisf90ae202002-06-11 06:22:31 +00006import sys
Fred Drake2ec80fa2000-10-23 16:59:35 +00007import os
Georg Brandl442b49e2006-06-08 14:50:53 +00008import unittest
Neal Norwitz62f5a9d2002-04-01 00:09:00 +00009from array import array
Raymond Hettingercb87bc82004-05-31 00:35:52 +000010from weakref import proxy
Fred Drake2ec80fa2000-10-23 16:59:35 +000011
Antoine Pitrou19690592009-06-12 20:14:08 +000012import io
13import _pyio as pyio
14
Serhiy Storchaka23999152018-06-08 20:24:19 +030015from test.support import TESTFN, run_unittest
16from test import support
Marc-André Lemburgfa44d792000-08-25 22:37:31 +000017from UserList import UserList
18
Georg Brandl442b49e2006-06-08 14:50:53 +000019class AutoFileTests(unittest.TestCase):
20 # file tests for which a test file is automatically set up
Raymond Hettingercb87bc82004-05-31 00:35:52 +000021
Georg Brandl442b49e2006-06-08 14:50:53 +000022 def setUp(self):
Antoine Pitrou19690592009-06-12 20:14:08 +000023 self.f = self.open(TESTFN, 'wb')
Tim Peters015dd822003-05-04 04:16:52 +000024
Georg Brandl442b49e2006-06-08 14:50:53 +000025 def tearDown(self):
Tim Petersdbb82f62006-06-09 03:51:41 +000026 if self.f:
27 self.f.close()
Serhiy Storchaka23999152018-06-08 20:24:19 +030028 support.unlink(TESTFN)
Georg Brandl442b49e2006-06-08 14:50:53 +000029
30 def testWeakRefs(self):
31 # verify weak references
32 p = proxy(self.f)
Antoine Pitrou19690592009-06-12 20:14:08 +000033 p.write(b'teststring')
Ezio Melotti2623a372010-11-21 13:34:58 +000034 self.assertEqual(self.f.tell(), p.tell())
Georg Brandl442b49e2006-06-08 14:50:53 +000035 self.f.close()
36 self.f = None
37 self.assertRaises(ReferenceError, getattr, p, 'tell')
38
39 def testAttributes(self):
40 # verify expected attributes exist
41 f = self.f
Georg Brandl442b49e2006-06-08 14:50:53 +000042 f.name # merely shouldn't blow up
43 f.mode # ditto
44 f.closed # ditto
45
Georg Brandl442b49e2006-06-08 14:50:53 +000046 def testReadinto(self):
47 # verify readinto
Antoine Pitrou19690592009-06-12 20:14:08 +000048 self.f.write(b'12')
Georg Brandl442b49e2006-06-08 14:50:53 +000049 self.f.close()
Antoine Pitrou19690592009-06-12 20:14:08 +000050 a = array('b', b'x'*10)
51 self.f = self.open(TESTFN, 'rb')
Georg Brandl442b49e2006-06-08 14:50:53 +000052 n = self.f.readinto(a)
Ezio Melotti2623a372010-11-21 13:34:58 +000053 self.assertEqual(b'12', a.tostring()[:n])
Antoine Pitrou19690592009-06-12 20:14:08 +000054
55 def testReadinto_text(self):
56 # verify readinto refuses text files
57 a = array('b', b'x'*10)
58 self.f.close()
59 self.f = self.open(TESTFN, 'r')
60 if hasattr(self.f, "readinto"):
61 self.assertRaises(TypeError, self.f.readinto, a)
Georg Brandl442b49e2006-06-08 14:50:53 +000062
63 def testWritelinesUserList(self):
64 # verify writelines with instance sequence
Antoine Pitrou19690592009-06-12 20:14:08 +000065 l = UserList([b'1', b'2'])
Georg Brandl442b49e2006-06-08 14:50:53 +000066 self.f.writelines(l)
67 self.f.close()
Antoine Pitrou19690592009-06-12 20:14:08 +000068 self.f = self.open(TESTFN, 'rb')
Georg Brandl442b49e2006-06-08 14:50:53 +000069 buf = self.f.read()
Ezio Melotti2623a372010-11-21 13:34:58 +000070 self.assertEqual(buf, b'12')
Georg Brandl442b49e2006-06-08 14:50:53 +000071
72 def testWritelinesIntegers(self):
73 # verify writelines with integers
74 self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
75
76 def testWritelinesIntegersUserList(self):
77 # verify writelines with integers in UserList
78 l = UserList([1,2,3])
79 self.assertRaises(TypeError, self.f.writelines, l)
80
81 def testWritelinesNonString(self):
82 # verify writelines with non-string object
Tim Petersdbb82f62006-06-09 03:51:41 +000083 class NonString:
84 pass
Georg Brandl442b49e2006-06-08 14:50:53 +000085
Tim Petersdbb82f62006-06-09 03:51:41 +000086 self.assertRaises(TypeError, self.f.writelines,
87 [NonString(), NonString()])
Georg Brandl442b49e2006-06-08 14:50:53 +000088
Georg Brandl442b49e2006-06-08 14:50:53 +000089 def testErrors(self):
90 f = self.f
Ezio Melotti2623a372010-11-21 13:34:58 +000091 self.assertEqual(f.name, TESTFN)
Serhiy Storchakaea4d2872015-08-02 15:19:04 +030092 self.assertFalse(f.isatty())
93 self.assertFalse(f.closed)
Tim Peters520d8dd2006-06-09 02:11:02 +000094
Antoine Pitrou19690592009-06-12 20:14:08 +000095 if hasattr(f, "readinto"):
96 self.assertRaises((IOError, TypeError), f.readinto, "")
Georg Brandl442b49e2006-06-08 14:50:53 +000097 f.close()
Benjamin Peterson5c8da862009-06-30 22:57:08 +000098 self.assertTrue(f.closed)
Georg Brandl442b49e2006-06-08 14:50:53 +000099
100 def testMethods(self):
Antoine Pitrou19690592009-06-12 20:14:08 +0000101 methods = [('fileno', ()),
102 ('flush', ()),
103 ('isatty', ()),
104 ('next', ()),
105 ('read', ()),
106 ('write', (b"",)),
107 ('readline', ()),
108 ('readlines', ()),
109 ('seek', (0,)),
110 ('tell', ()),
111 ('write', (b"",)),
112 ('writelines', ([],)),
113 ('__iter__', ()),
114 ]
115 if not sys.platform.startswith('atheos'):
116 methods.append(('truncate', ()))
Georg Brandl442b49e2006-06-08 14:50:53 +0000117
Georg Brandle7ec81f2006-06-09 18:29:52 +0000118 # __exit__ should close the file
119 self.f.__exit__(None, None, None)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000120 self.assertTrue(self.f.closed)
Georg Brandl442b49e2006-06-08 14:50:53 +0000121
Antoine Pitrou19690592009-06-12 20:14:08 +0000122 for methodname, args in methods:
Georg Brandl442b49e2006-06-08 14:50:53 +0000123 method = getattr(self.f, methodname)
124 # should raise on closed file
Antoine Pitrou19690592009-06-12 20:14:08 +0000125 self.assertRaises(ValueError, method, *args)
Georg Brandl442b49e2006-06-08 14:50:53 +0000126
Georg Brandle7ec81f2006-06-09 18:29:52 +0000127 # file is closed, __exit__ shouldn't do anything
Ezio Melotti2623a372010-11-21 13:34:58 +0000128 self.assertEqual(self.f.__exit__(None, None, None), None)
Georg Brandle7ec81f2006-06-09 18:29:52 +0000129 # it must also return None if an exception was given
130 try:
Ezio Melottidde5b942010-02-03 05:37:26 +0000131 1 // 0
Georg Brandle7ec81f2006-06-09 18:29:52 +0000132 except:
Ezio Melotti2623a372010-11-21 13:34:58 +0000133 self.assertEqual(self.f.__exit__(*sys.exc_info()), None)
Georg Brandle7ec81f2006-06-09 18:29:52 +0000134
Skip Montanarof205c132008-12-23 03:30:15 +0000135 def testReadWhenWriting(self):
136 self.assertRaises(IOError, self.f.read)
Georg Brandl442b49e2006-06-08 14:50:53 +0000137
Antoine Pitrou19690592009-06-12 20:14:08 +0000138class CAutoFileTests(AutoFileTests):
139 open = io.open
Georg Brandl442b49e2006-06-08 14:50:53 +0000140
Antoine Pitrou19690592009-06-12 20:14:08 +0000141class PyAutoFileTests(AutoFileTests):
142 open = staticmethod(pyio.open)
143
144
145class OtherFileTests(unittest.TestCase):
Benjamin Petersonfe231b02008-12-29 17:47:42 +0000146
Serhiy Storchaka23999152018-06-08 20:24:19 +0300147 def tearDown(self):
148 support.unlink(TESTFN)
149
Georg Brandl442b49e2006-06-08 14:50:53 +0000150 def testModeStrings(self):
151 # check invalid mode strings
Serhiy Storchaka23999152018-06-08 20:24:19 +0300152 self.open(TESTFN, 'wb').close()
Georg Brandl442b49e2006-06-08 14:50:53 +0000153 for mode in ("", "aU", "wU+"):
154 try:
Antoine Pitrou19690592009-06-12 20:14:08 +0000155 f = self.open(TESTFN, mode)
Georg Brandl442b49e2006-06-08 14:50:53 +0000156 except ValueError:
157 pass
158 else:
159 f.close()
160 self.fail('%r is an invalid file mode' % mode)
161
Georg Brandl442b49e2006-06-08 14:50:53 +0000162 def testBadModeArgument(self):
163 # verify that we get a sensible error message for bad mode argument
164 bad_mode = "qwerty"
Tim Peterscffcfed2006-02-14 17:41:18 +0000165 try:
Antoine Pitrou19690592009-06-12 20:14:08 +0000166 f = self.open(TESTFN, bad_mode)
167 except ValueError as msg:
168 if msg.args[0] != 0:
Georg Brandl442b49e2006-06-08 14:50:53 +0000169 s = str(msg)
Ezio Melotti187f93d2010-03-17 14:22:34 +0000170 if TESTFN in s or bad_mode not in s:
Georg Brandl442b49e2006-06-08 14:50:53 +0000171 self.fail("bad error message for invalid mode: %s" % s)
Antoine Pitrou19690592009-06-12 20:14:08 +0000172 # if msg.args[0] == 0, we're probably on Windows where there may be
Georg Brandl442b49e2006-06-08 14:50:53 +0000173 # no obvious way to discover why open() failed.
174 else:
175 f.close()
176 self.fail("no error for invalid mode: %s" % bad_mode)
177
178 def testSetBufferSize(self):
179 # make sure that explicitly setting the buffer size doesn't cause
180 # misbehaviour especially with repeated close() calls
181 for s in (-1, 0, 1, 512):
182 try:
Antoine Pitrou19690592009-06-12 20:14:08 +0000183 f = self.open(TESTFN, 'wb', s)
184 f.write(str(s).encode("ascii"))
Georg Brandl442b49e2006-06-08 14:50:53 +0000185 f.close()
186 f.close()
Antoine Pitrou19690592009-06-12 20:14:08 +0000187 f = self.open(TESTFN, 'rb', s)
188 d = int(f.read().decode("ascii"))
Georg Brandl442b49e2006-06-08 14:50:53 +0000189 f.close()
190 f.close()
Antoine Pitrou19690592009-06-12 20:14:08 +0000191 except IOError as msg:
Georg Brandl442b49e2006-06-08 14:50:53 +0000192 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
Ezio Melotti2623a372010-11-21 13:34:58 +0000193 self.assertEqual(d, s)
Georg Brandl442b49e2006-06-08 14:50:53 +0000194
195 def testTruncateOnWindows(self):
Antoine Pitrou19690592009-06-12 20:14:08 +0000196 # SF bug <http://www.python.org/sf/801631>
197 # "file.truncate fault on windows"
Georg Brandl442b49e2006-06-08 14:50:53 +0000198
Antoine Pitrou19690592009-06-12 20:14:08 +0000199 f = self.open(TESTFN, 'wb')
200
201 try:
202 f.write(b'12345678901') # 11 bytes
Georg Brandl442b49e2006-06-08 14:50:53 +0000203 f.close()
204
Antoine Pitrou19690592009-06-12 20:14:08 +0000205 f = self.open(TESTFN,'rb+')
Georg Brandl442b49e2006-06-08 14:50:53 +0000206 data = f.read(5)
Antoine Pitrou19690592009-06-12 20:14:08 +0000207 if data != b'12345':
Georg Brandl442b49e2006-06-08 14:50:53 +0000208 self.fail("Read on file opened for update failed %r" % data)
209 if f.tell() != 5:
210 self.fail("File pos after read wrong %d" % f.tell())
211
212 f.truncate()
213 if f.tell() != 5:
214 self.fail("File pos after ftruncate wrong %d" % f.tell())
215
216 f.close()
217 size = os.path.getsize(TESTFN)
218 if size != 5:
219 self.fail("File size after ftruncate wrong %d" % size)
Georg Brandl442b49e2006-06-08 14:50:53 +0000220 finally:
Antoine Pitrou19690592009-06-12 20:14:08 +0000221 f.close()
Georg Brandl442b49e2006-06-08 14:50:53 +0000222
223 def testIteration(self):
Tim Petersdbb82f62006-06-09 03:51:41 +0000224 # Test the complex interaction when mixing file-iteration and the
Antoine Pitrou19690592009-06-12 20:14:08 +0000225 # various read* methods.
Georg Brandl442b49e2006-06-08 14:50:53 +0000226 dataoffset = 16384
Antoine Pitrou19690592009-06-12 20:14:08 +0000227 filler = b"ham\n"
Georg Brandl442b49e2006-06-08 14:50:53 +0000228 assert not dataoffset % len(filler), \
229 "dataoffset must be multiple of len(filler)"
230 nchunks = dataoffset // len(filler)
231 testlines = [
Antoine Pitrou19690592009-06-12 20:14:08 +0000232 b"spam, spam and eggs\n",
233 b"eggs, spam, ham and spam\n",
234 b"saussages, spam, spam and eggs\n",
235 b"spam, ham, spam and eggs\n",
236 b"spam, spam, spam, spam, spam, ham, spam\n",
237 b"wonderful spaaaaaam.\n"
Georg Brandl442b49e2006-06-08 14:50:53 +0000238 ]
239 methods = [("readline", ()), ("read", ()), ("readlines", ()),
Antoine Pitrou19690592009-06-12 20:14:08 +0000240 ("readinto", (array("b", b" "*100),))]
Georg Brandl442b49e2006-06-08 14:50:53 +0000241
Serhiy Storchaka23999152018-06-08 20:24:19 +0300242 # Prepare the testfile
243 bag = self.open(TESTFN, "wb")
244 bag.write(filler * nchunks)
245 bag.writelines(testlines)
246 bag.close()
247 # Test for appropriate errors mixing read* and iteration
248 for methodname, args in methods:
Antoine Pitrou19690592009-06-12 20:14:08 +0000249 f = self.open(TESTFN, 'rb')
Serhiy Storchaka23999152018-06-08 20:24:19 +0300250 if next(f) != filler:
251 self.fail, "Broken testfile"
252 meth = getattr(f, methodname)
253 meth(*args) # This simply shouldn't fail
Benjamin Peterson7b26a5a2014-04-04 13:56:26 -0400254 f.close()
Serhiy Storchaka23999152018-06-08 20:24:19 +0300255
256 # Test to see if harmless (by accident) mixing of read* and
257 # iteration still works. This depends on the size of the internal
258 # iteration buffer (currently 8192,) but we can test it in a
259 # flexible manner. Each line in the bag o' ham is 4 bytes
260 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
261 # exactly on the buffer boundary for any power-of-2 buffersize
262 # between 4 and 16384 (inclusive).
263 f = self.open(TESTFN, 'rb')
264 for i in range(nchunks):
265 next(f)
266 testline = testlines.pop(0)
267 try:
268 line = f.readline()
269 except ValueError:
270 self.fail("readline() after next() with supposedly empty "
271 "iteration-buffer failed anyway")
272 if line != testline:
273 self.fail("readline() after next() with empty buffer "
274 "failed. Got %r, expected %r" % (line, testline))
275 testline = testlines.pop(0)
276 buf = array("b", b"\x00" * len(testline))
277 try:
278 f.readinto(buf)
279 except ValueError:
280 self.fail("readinto() after next() with supposedly empty "
281 "iteration-buffer failed anyway")
282 line = buf.tostring()
283 if line != testline:
284 self.fail("readinto() after next() with empty buffer "
285 "failed. Got %r, expected %r" % (line, testline))
286
287 testline = testlines.pop(0)
288 try:
289 line = f.read(len(testline))
290 except ValueError:
291 self.fail("read() after next() with supposedly empty "
292 "iteration-buffer failed anyway")
293 if line != testline:
294 self.fail("read() after next() with empty buffer "
295 "failed. Got %r, expected %r" % (line, testline))
296 try:
297 lines = f.readlines()
298 except ValueError:
299 self.fail("readlines() after next() with supposedly empty "
300 "iteration-buffer failed anyway")
301 if lines != testlines:
302 self.fail("readlines() after next() with empty buffer "
303 "failed. Got %r, expected %r" % (line, testline))
304 # Reading after iteration hit EOF shouldn't hurt either
305 f.close()
306 f = self.open(TESTFN, 'rb')
307 try:
308 for line in f:
309 pass
Georg Brandl442b49e2006-06-08 14:50:53 +0000310 try:
Serhiy Storchaka23999152018-06-08 20:24:19 +0300311 f.readline()
312 f.readinto(buf)
313 f.read()
314 f.readlines()
315 except ValueError:
316 self.fail("read* failed after next() consumed file")
Georg Brandl442b49e2006-06-08 14:50:53 +0000317 finally:
Serhiy Storchaka23999152018-06-08 20:24:19 +0300318 f.close()
Georg Brandl442b49e2006-06-08 14:50:53 +0000319
Antoine Pitrou19690592009-06-12 20:14:08 +0000320class COtherFileTests(OtherFileTests):
321 open = io.open
Georg Brandlad61bc82008-02-23 15:11:18 +0000322
Antoine Pitrou19690592009-06-12 20:14:08 +0000323class PyOtherFileTests(OtherFileTests):
324 open = staticmethod(pyio.open)
Jeffrey Yasskin2d873bd2008-12-08 18:55:24 +0000325
Gregory P. Smithaa63d0d2008-04-06 23:11:17 +0000326
Georg Brandl442b49e2006-06-08 14:50:53 +0000327def test_main():
Serhiy Storchaka23999152018-06-08 20:24:19 +0300328 run_unittest(CAutoFileTests, PyAutoFileTests,
329 COtherFileTests, PyOtherFileTests)
Georg Brandl442b49e2006-06-08 14:50:53 +0000330
331if __name__ == '__main__':
332 test_main()