blob: 4f2c9ef5b6034a5adc1238c5f24a99fd81f7e5ff [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
Georg Brandla4f46e12010-02-07 17:03:15 +000015from test.test_support import TESTFN, run_unittest
Marc-André Lemburgfa44d792000-08-25 22:37:31 +000016from UserList import UserList
17
Georg Brandl442b49e2006-06-08 14:50:53 +000018class AutoFileTests(unittest.TestCase):
19 # file tests for which a test file is automatically set up
Raymond Hettingercb87bc82004-05-31 00:35:52 +000020
Georg Brandl442b49e2006-06-08 14:50:53 +000021 def setUp(self):
Antoine Pitrou19690592009-06-12 20:14:08 +000022 self.f = self.open(TESTFN, 'wb')
Tim Peters015dd822003-05-04 04:16:52 +000023
Georg Brandl442b49e2006-06-08 14:50:53 +000024 def tearDown(self):
Tim Petersdbb82f62006-06-09 03:51:41 +000025 if self.f:
26 self.f.close()
27 os.remove(TESTFN)
Georg Brandl442b49e2006-06-08 14:50:53 +000028
29 def testWeakRefs(self):
30 # verify weak references
31 p = proxy(self.f)
Antoine Pitrou19690592009-06-12 20:14:08 +000032 p.write(b'teststring')
Ezio Melotti2623a372010-11-21 13:34:58 +000033 self.assertEqual(self.f.tell(), p.tell())
Georg Brandl442b49e2006-06-08 14:50:53 +000034 self.f.close()
35 self.f = None
36 self.assertRaises(ReferenceError, getattr, p, 'tell')
37
38 def testAttributes(self):
39 # verify expected attributes exist
40 f = self.f
Georg Brandl442b49e2006-06-08 14:50:53 +000041 f.name # merely shouldn't blow up
42 f.mode # ditto
43 f.closed # ditto
44
Georg Brandl442b49e2006-06-08 14:50:53 +000045 def testReadinto(self):
46 # verify readinto
Antoine Pitrou19690592009-06-12 20:14:08 +000047 self.f.write(b'12')
Georg Brandl442b49e2006-06-08 14:50:53 +000048 self.f.close()
Antoine Pitrou19690592009-06-12 20:14:08 +000049 a = array('b', b'x'*10)
50 self.f = self.open(TESTFN, 'rb')
Georg Brandl442b49e2006-06-08 14:50:53 +000051 n = self.f.readinto(a)
Ezio Melotti2623a372010-11-21 13:34:58 +000052 self.assertEqual(b'12', a.tostring()[:n])
Antoine Pitrou19690592009-06-12 20:14:08 +000053
54 def testReadinto_text(self):
55 # verify readinto refuses text files
56 a = array('b', b'x'*10)
57 self.f.close()
58 self.f = self.open(TESTFN, 'r')
59 if hasattr(self.f, "readinto"):
60 self.assertRaises(TypeError, self.f.readinto, a)
Georg Brandl442b49e2006-06-08 14:50:53 +000061
62 def testWritelinesUserList(self):
63 # verify writelines with instance sequence
Antoine Pitrou19690592009-06-12 20:14:08 +000064 l = UserList([b'1', b'2'])
Georg Brandl442b49e2006-06-08 14:50:53 +000065 self.f.writelines(l)
66 self.f.close()
Antoine Pitrou19690592009-06-12 20:14:08 +000067 self.f = self.open(TESTFN, 'rb')
Georg Brandl442b49e2006-06-08 14:50:53 +000068 buf = self.f.read()
Ezio Melotti2623a372010-11-21 13:34:58 +000069 self.assertEqual(buf, b'12')
Georg Brandl442b49e2006-06-08 14:50:53 +000070
71 def testWritelinesIntegers(self):
72 # verify writelines with integers
73 self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
74
75 def testWritelinesIntegersUserList(self):
76 # verify writelines with integers in UserList
77 l = UserList([1,2,3])
78 self.assertRaises(TypeError, self.f.writelines, l)
79
80 def testWritelinesNonString(self):
81 # verify writelines with non-string object
Tim Petersdbb82f62006-06-09 03:51:41 +000082 class NonString:
83 pass
Georg Brandl442b49e2006-06-08 14:50:53 +000084
Tim Petersdbb82f62006-06-09 03:51:41 +000085 self.assertRaises(TypeError, self.f.writelines,
86 [NonString(), NonString()])
Georg Brandl442b49e2006-06-08 14:50:53 +000087
Georg Brandl442b49e2006-06-08 14:50:53 +000088 def testErrors(self):
89 f = self.f
Ezio Melotti2623a372010-11-21 13:34:58 +000090 self.assertEqual(f.name, TESTFN)
Benjamin Peterson5c8da862009-06-30 22:57:08 +000091 self.assertTrue(not f.isatty())
92 self.assertTrue(not f.closed)
Tim Peters520d8dd2006-06-09 02:11:02 +000093
Antoine Pitrou19690592009-06-12 20:14:08 +000094 if hasattr(f, "readinto"):
95 self.assertRaises((IOError, TypeError), f.readinto, "")
Georg Brandl442b49e2006-06-08 14:50:53 +000096 f.close()
Benjamin Peterson5c8da862009-06-30 22:57:08 +000097 self.assertTrue(f.closed)
Georg Brandl442b49e2006-06-08 14:50:53 +000098
99 def testMethods(self):
Antoine Pitrou19690592009-06-12 20:14:08 +0000100 methods = [('fileno', ()),
101 ('flush', ()),
102 ('isatty', ()),
103 ('next', ()),
104 ('read', ()),
105 ('write', (b"",)),
106 ('readline', ()),
107 ('readlines', ()),
108 ('seek', (0,)),
109 ('tell', ()),
110 ('write', (b"",)),
111 ('writelines', ([],)),
112 ('__iter__', ()),
113 ]
114 if not sys.platform.startswith('atheos'):
115 methods.append(('truncate', ()))
Georg Brandl442b49e2006-06-08 14:50:53 +0000116
Georg Brandle7ec81f2006-06-09 18:29:52 +0000117 # __exit__ should close the file
118 self.f.__exit__(None, None, None)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000119 self.assertTrue(self.f.closed)
Georg Brandl442b49e2006-06-08 14:50:53 +0000120
Antoine Pitrou19690592009-06-12 20:14:08 +0000121 for methodname, args in methods:
Georg Brandl442b49e2006-06-08 14:50:53 +0000122 method = getattr(self.f, methodname)
123 # should raise on closed file
Antoine Pitrou19690592009-06-12 20:14:08 +0000124 self.assertRaises(ValueError, method, *args)
Georg Brandl442b49e2006-06-08 14:50:53 +0000125
Georg Brandle7ec81f2006-06-09 18:29:52 +0000126 # file is closed, __exit__ shouldn't do anything
Ezio Melotti2623a372010-11-21 13:34:58 +0000127 self.assertEqual(self.f.__exit__(None, None, None), None)
Georg Brandle7ec81f2006-06-09 18:29:52 +0000128 # it must also return None if an exception was given
129 try:
Ezio Melottidde5b942010-02-03 05:37:26 +0000130 1 // 0
Georg Brandle7ec81f2006-06-09 18:29:52 +0000131 except:
Ezio Melotti2623a372010-11-21 13:34:58 +0000132 self.assertEqual(self.f.__exit__(*sys.exc_info()), None)
Georg Brandle7ec81f2006-06-09 18:29:52 +0000133
Skip Montanarof205c132008-12-23 03:30:15 +0000134 def testReadWhenWriting(self):
135 self.assertRaises(IOError, self.f.read)
Georg Brandl442b49e2006-06-08 14:50:53 +0000136
Antoine Pitrou19690592009-06-12 20:14:08 +0000137class CAutoFileTests(AutoFileTests):
138 open = io.open
Georg Brandl442b49e2006-06-08 14:50:53 +0000139
Antoine Pitrou19690592009-06-12 20:14:08 +0000140class PyAutoFileTests(AutoFileTests):
141 open = staticmethod(pyio.open)
142
143
144class OtherFileTests(unittest.TestCase):
Benjamin Petersonfe231b02008-12-29 17:47:42 +0000145
Georg Brandl442b49e2006-06-08 14:50:53 +0000146 def testModeStrings(self):
147 # check invalid mode strings
148 for mode in ("", "aU", "wU+"):
149 try:
Antoine Pitrou19690592009-06-12 20:14:08 +0000150 f = self.open(TESTFN, mode)
Georg Brandl442b49e2006-06-08 14:50:53 +0000151 except ValueError:
152 pass
153 else:
154 f.close()
155 self.fail('%r is an invalid file mode' % mode)
156
Georg Brandl442b49e2006-06-08 14:50:53 +0000157 def testBadModeArgument(self):
158 # verify that we get a sensible error message for bad mode argument
159 bad_mode = "qwerty"
Tim Peterscffcfed2006-02-14 17:41:18 +0000160 try:
Antoine Pitrou19690592009-06-12 20:14:08 +0000161 f = self.open(TESTFN, bad_mode)
162 except ValueError as msg:
163 if msg.args[0] != 0:
Georg Brandl442b49e2006-06-08 14:50:53 +0000164 s = str(msg)
Ezio Melotti187f93d2010-03-17 14:22:34 +0000165 if TESTFN in s or bad_mode not in s:
Georg Brandl442b49e2006-06-08 14:50:53 +0000166 self.fail("bad error message for invalid mode: %s" % s)
Antoine Pitrou19690592009-06-12 20:14:08 +0000167 # if msg.args[0] == 0, we're probably on Windows where there may be
Georg Brandl442b49e2006-06-08 14:50:53 +0000168 # no obvious way to discover why open() failed.
169 else:
170 f.close()
171 self.fail("no error for invalid mode: %s" % bad_mode)
172
173 def testSetBufferSize(self):
174 # make sure that explicitly setting the buffer size doesn't cause
175 # misbehaviour especially with repeated close() calls
176 for s in (-1, 0, 1, 512):
177 try:
Antoine Pitrou19690592009-06-12 20:14:08 +0000178 f = self.open(TESTFN, 'wb', s)
179 f.write(str(s).encode("ascii"))
Georg Brandl442b49e2006-06-08 14:50:53 +0000180 f.close()
181 f.close()
Antoine Pitrou19690592009-06-12 20:14:08 +0000182 f = self.open(TESTFN, 'rb', s)
183 d = int(f.read().decode("ascii"))
Georg Brandl442b49e2006-06-08 14:50:53 +0000184 f.close()
185 f.close()
Antoine Pitrou19690592009-06-12 20:14:08 +0000186 except IOError as msg:
Georg Brandl442b49e2006-06-08 14:50:53 +0000187 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
Ezio Melotti2623a372010-11-21 13:34:58 +0000188 self.assertEqual(d, s)
Georg Brandl442b49e2006-06-08 14:50:53 +0000189
190 def testTruncateOnWindows(self):
Antoine Pitrou19690592009-06-12 20:14:08 +0000191 # SF bug <http://www.python.org/sf/801631>
192 # "file.truncate fault on windows"
Georg Brandl442b49e2006-06-08 14:50:53 +0000193
Antoine Pitrou19690592009-06-12 20:14:08 +0000194 os.unlink(TESTFN)
195 f = self.open(TESTFN, 'wb')
196
197 try:
198 f.write(b'12345678901') # 11 bytes
Georg Brandl442b49e2006-06-08 14:50:53 +0000199 f.close()
200
Antoine Pitrou19690592009-06-12 20:14:08 +0000201 f = self.open(TESTFN,'rb+')
Georg Brandl442b49e2006-06-08 14:50:53 +0000202 data = f.read(5)
Antoine Pitrou19690592009-06-12 20:14:08 +0000203 if data != b'12345':
Georg Brandl442b49e2006-06-08 14:50:53 +0000204 self.fail("Read on file opened for update failed %r" % data)
205 if f.tell() != 5:
206 self.fail("File pos after read wrong %d" % f.tell())
207
208 f.truncate()
209 if f.tell() != 5:
210 self.fail("File pos after ftruncate wrong %d" % f.tell())
211
212 f.close()
213 size = os.path.getsize(TESTFN)
214 if size != 5:
215 self.fail("File size after ftruncate wrong %d" % size)
Georg Brandl442b49e2006-06-08 14:50:53 +0000216 finally:
Antoine Pitrou19690592009-06-12 20:14:08 +0000217 f.close()
Georg Brandl442b49e2006-06-08 14:50:53 +0000218 os.unlink(TESTFN)
219
220 def testIteration(self):
Tim Petersdbb82f62006-06-09 03:51:41 +0000221 # Test the complex interaction when mixing file-iteration and the
Antoine Pitrou19690592009-06-12 20:14:08 +0000222 # various read* methods.
Georg Brandl442b49e2006-06-08 14:50:53 +0000223 dataoffset = 16384
Antoine Pitrou19690592009-06-12 20:14:08 +0000224 filler = b"ham\n"
Georg Brandl442b49e2006-06-08 14:50:53 +0000225 assert not dataoffset % len(filler), \
226 "dataoffset must be multiple of len(filler)"
227 nchunks = dataoffset // len(filler)
228 testlines = [
Antoine Pitrou19690592009-06-12 20:14:08 +0000229 b"spam, spam and eggs\n",
230 b"eggs, spam, ham and spam\n",
231 b"saussages, spam, spam and eggs\n",
232 b"spam, ham, spam and eggs\n",
233 b"spam, spam, spam, spam, spam, ham, spam\n",
234 b"wonderful spaaaaaam.\n"
Georg Brandl442b49e2006-06-08 14:50:53 +0000235 ]
236 methods = [("readline", ()), ("read", ()), ("readlines", ()),
Antoine Pitrou19690592009-06-12 20:14:08 +0000237 ("readinto", (array("b", b" "*100),))]
Georg Brandl442b49e2006-06-08 14:50:53 +0000238
239 try:
240 # Prepare the testfile
Antoine Pitrou19690592009-06-12 20:14:08 +0000241 bag = self.open(TESTFN, "wb")
Georg Brandl442b49e2006-06-08 14:50:53 +0000242 bag.write(filler * nchunks)
243 bag.writelines(testlines)
244 bag.close()
245 # Test for appropriate errors mixing read* and iteration
246 for methodname, args in methods:
Antoine Pitrou19690592009-06-12 20:14:08 +0000247 f = self.open(TESTFN, 'rb')
248 if next(f) != filler:
Georg Brandl442b49e2006-06-08 14:50:53 +0000249 self.fail, "Broken testfile"
250 meth = getattr(f, methodname)
Antoine Pitrou19690592009-06-12 20:14:08 +0000251 meth(*args) # This simply shouldn't fail
Georg Brandl442b49e2006-06-08 14:50:53 +0000252 f.close()
253
Tim Petersdbb82f62006-06-09 03:51:41 +0000254 # Test to see if harmless (by accident) mixing of read* and
255 # iteration still works. This depends on the size of the internal
256 # iteration buffer (currently 8192,) but we can test it in a
257 # flexible manner. Each line in the bag o' ham is 4 bytes
258 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
259 # exactly on the buffer boundary for any power-of-2 buffersize
260 # between 4 and 16384 (inclusive).
Antoine Pitrou19690592009-06-12 20:14:08 +0000261 f = self.open(TESTFN, 'rb')
Georg Brandl442b49e2006-06-08 14:50:53 +0000262 for i in range(nchunks):
Antoine Pitrou19690592009-06-12 20:14:08 +0000263 next(f)
Georg Brandl442b49e2006-06-08 14:50:53 +0000264 testline = testlines.pop(0)
265 try:
266 line = f.readline()
267 except ValueError:
268 self.fail("readline() after next() with supposedly empty "
269 "iteration-buffer failed anyway")
270 if line != testline:
271 self.fail("readline() after next() with empty buffer "
272 "failed. Got %r, expected %r" % (line, testline))
273 testline = testlines.pop(0)
Antoine Pitrou19690592009-06-12 20:14:08 +0000274 buf = array("b", b"\x00" * len(testline))
Georg Brandl442b49e2006-06-08 14:50:53 +0000275 try:
276 f.readinto(buf)
277 except ValueError:
278 self.fail("readinto() after next() with supposedly empty "
279 "iteration-buffer failed anyway")
280 line = buf.tostring()
281 if line != testline:
282 self.fail("readinto() after next() with empty buffer "
283 "failed. Got %r, expected %r" % (line, testline))
284
285 testline = testlines.pop(0)
286 try:
287 line = f.read(len(testline))
288 except ValueError:
289 self.fail("read() after next() with supposedly empty "
290 "iteration-buffer failed anyway")
291 if line != testline:
292 self.fail("read() after next() with empty buffer "
293 "failed. Got %r, expected %r" % (line, testline))
294 try:
295 lines = f.readlines()
296 except ValueError:
297 self.fail("readlines() after next() with supposedly empty "
298 "iteration-buffer failed anyway")
299 if lines != testlines:
300 self.fail("readlines() after next() with empty buffer "
301 "failed. Got %r, expected %r" % (line, testline))
302 # Reading after iteration hit EOF shouldn't hurt either
Benjamin Peterson7b26a5a2014-04-04 13:56:26 -0400303 f.close()
Antoine Pitrou19690592009-06-12 20:14:08 +0000304 f = self.open(TESTFN, 'rb')
Georg Brandl442b49e2006-06-08 14:50:53 +0000305 try:
306 for line in f:
307 pass
308 try:
309 f.readline()
310 f.readinto(buf)
311 f.read()
312 f.readlines()
313 except ValueError:
314 self.fail("read* failed after next() consumed file")
315 finally:
316 f.close()
317 finally:
318 os.unlink(TESTFN)
319
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():
Neal Norwitzc9778a82006-06-09 05:54:18 +0000328 # Historically, these tests have been sloppy about removing TESTFN.
329 # So get rid of it no matter what.
Tim Peters0556e9b2006-06-09 04:02:06 +0000330 try:
Antoine Pitrou19690592009-06-12 20:14:08 +0000331 run_unittest(CAutoFileTests, PyAutoFileTests,
332 COtherFileTests, PyOtherFileTests)
Tim Peters0556e9b2006-06-09 04:02:06 +0000333 finally:
334 if os.path.exists(TESTFN):
335 os.unlink(TESTFN)
Georg Brandl442b49e2006-06-08 14:50:53 +0000336
337if __name__ == '__main__':
338 test_main()