blob: 1ec756f334d28f784beb993f9554e763d5477b8d [file] [log] [blame]
Martin v. Löwisf90ae202002-06-11 06:22:31 +00001import sys
Fred Drake2ec80fa2000-10-23 16:59:35 +00002import os
Thomas Wouters73e5a5b2006-06-08 15:35:45 +00003import unittest
Neal Norwitz62f5a9d2002-04-01 00:09:00 +00004from array import array
Raymond Hettingercb87bc82004-05-31 00:35:52 +00005from weakref import proxy
Fred Drake2ec80fa2000-10-23 16:59:35 +00006
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +00007import io
8import _pyio as pyio
9
Hai Shia089d212020-07-06 17:15:08 +080010from test.support.os_helper import TESTFN
11from test.support import os_helper
12from test.support import warnings_helper
Raymond Hettinger53dbe392008-02-12 20:03:09 +000013from collections import UserList
Marc-André Lemburgfa44d792000-08-25 22:37:31 +000014
Ezio Melotti3a03d2e2013-02-15 19:17:53 +020015class AutoFileTests:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000016 # file tests for which a test file is automatically set up
Raymond Hettingercb87bc82004-05-31 00:35:52 +000017
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000018 def setUp(self):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000019 self.f = self.open(TESTFN, 'wb')
Tim Peters015dd822003-05-04 04:16:52 +000020
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000021 def tearDown(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000022 if self.f:
23 self.f.close()
Hai Shia089d212020-07-06 17:15:08 +080024 os_helper.unlink(TESTFN)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000025
26 def testWeakRefs(self):
27 # verify weak references
28 p = proxy(self.f)
Guido van Rossume22905a2007-08-27 23:09:25 +000029 p.write(b'teststring')
Ezio Melottib3aedd42010-11-20 19:04:17 +000030 self.assertEqual(self.f.tell(), p.tell())
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000031 self.f.close()
32 self.f = None
33 self.assertRaises(ReferenceError, getattr, p, 'tell')
34
35 def testAttributes(self):
36 # verify expected attributes exist
37 f = self.f
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000038 f.name # merely shouldn't blow up
39 f.mode # ditto
40 f.closed # ditto
41
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000042 def testReadinto(self):
43 # verify readinto
Guido van Rossume22905a2007-08-27 23:09:25 +000044 self.f.write(b'12')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000045 self.f.close()
Guido van Rossum7165cb12007-07-10 06:54:34 +000046 a = array('b', b'x'*10)
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000047 self.f = self.open(TESTFN, 'rb')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000048 n = self.f.readinto(a)
Ezio Melottib3aedd42010-11-20 19:04:17 +000049 self.assertEqual(b'12', a.tobytes()[:n])
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000050
51 def testReadinto_text(self):
52 # verify readinto refuses text files
Guido van Rossum7165cb12007-07-10 06:54:34 +000053 a = array('b', b'x'*10)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000054 self.f.close()
Inada Naoki55f31be2021-04-01 11:23:03 +090055 self.f = self.open(TESTFN, encoding="utf-8")
Guido van Rossum7165cb12007-07-10 06:54:34 +000056 if hasattr(self.f, "readinto"):
57 self.assertRaises(TypeError, self.f.readinto, a)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000058
59 def testWritelinesUserList(self):
60 # verify writelines with instance sequence
Guido van Rossum7165cb12007-07-10 06:54:34 +000061 l = UserList([b'1', b'2'])
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000062 self.f.writelines(l)
63 self.f.close()
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000064 self.f = self.open(TESTFN, 'rb')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000065 buf = self.f.read()
Ezio Melottib3aedd42010-11-20 19:04:17 +000066 self.assertEqual(buf, b'12')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000067
68 def testWritelinesIntegers(self):
69 # verify writelines with integers
70 self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
71
72 def testWritelinesIntegersUserList(self):
73 # verify writelines with integers in UserList
74 l = UserList([1,2,3])
75 self.assertRaises(TypeError, self.f.writelines, l)
76
77 def testWritelinesNonString(self):
78 # verify writelines with non-string object
Thomas Wouters0e3f5912006-08-11 14:57:12 +000079 class NonString:
80 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000081
Thomas Wouters0e3f5912006-08-11 14:57:12 +000082 self.assertRaises(TypeError, self.f.writelines,
83 [NonString(), NonString()])
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000084
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000085 def testErrors(self):
86 f = self.f
Ezio Melottib3aedd42010-11-20 19:04:17 +000087 self.assertEqual(f.name, TESTFN)
Serhiy Storchaka0dcd80a2015-08-02 15:17:49 +030088 self.assertFalse(f.isatty())
89 self.assertFalse(f.closed)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000090
Guido van Rossum7165cb12007-07-10 06:54:34 +000091 if hasattr(f, "readinto"):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +020092 self.assertRaises((OSError, TypeError), f.readinto, "")
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000093 f.close()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000094 self.assertTrue(f.closed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000095
96 def testMethods(self):
Guido van Rossum4b5386f2007-07-10 09:12:49 +000097 methods = [('fileno', ()),
98 ('flush', ()),
99 ('isatty', ()),
100 ('__next__', ()),
101 ('read', ()),
102 ('write', (b"",)),
103 ('readline', ()),
104 ('readlines', ()),
105 ('seek', (0,)),
106 ('tell', ()),
107 ('write', (b"",)),
108 ('writelines', ([],)),
109 ('__iter__', ()),
110 ]
Antoine Pitrou6103ab12009-10-24 20:11:21 +0000111 methods.append(('truncate', ()))
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000112
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000113 # __exit__ should close the file
114 self.f.__exit__(None, None, None)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000115 self.assertTrue(self.f.closed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000116
Guido van Rossum4b5386f2007-07-10 09:12:49 +0000117 for methodname, args in methods:
118 method = getattr(self.f, methodname)
119 # should raise on closed file
120 self.assertRaises(ValueError, method, *args)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000121
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000122 # file is closed, __exit__ shouldn't do anything
Ezio Melottib3aedd42010-11-20 19:04:17 +0000123 self.assertEqual(self.f.__exit__(None, None, None), None)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000124 # it must also return None if an exception was given
125 try:
126 1/0
127 except:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000128 self.assertEqual(self.f.__exit__(*sys.exc_info()), None)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000129
Skip Montanaro80072cb2008-12-23 03:51:14 +0000130 def testReadWhenWriting(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200131 self.assertRaises(OSError, self.f.read)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000132
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200133class CAutoFileTests(AutoFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000134 open = io.open
135
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200136class PyAutoFileTests(AutoFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000137 open = staticmethod(pyio.open)
138
139
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200140class OtherFileTests:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000141
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300142 def tearDown(self):
Hai Shia089d212020-07-06 17:15:08 +0800143 os_helper.unlink(TESTFN)
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300144
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000145 def testModeStrings(self):
146 # check invalid mode strings
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300147 self.open(TESTFN, 'wb').close()
Robert Collinsc94a1dc2015-07-26 06:43:13 +1200148 for mode in ("", "aU", "wU+", "U+", "+U", "rU+"):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000149 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000150 f = self.open(TESTFN, mode)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000151 except ValueError:
152 pass
153 else:
154 f.close()
155 self.fail('%r is an invalid file mode' % mode)
156
Miss Islington (bot)4e0147e2021-08-10 07:31:00 -0700157 def testStdin(self):
158 if sys.platform == 'osf1V5':
159 # This causes the interpreter to exit on OSF1 v5.1.
160 self.skipTest(
161 ' sys.stdin.seek(-1) may crash the interpreter on OSF1.'
162 ' Test manually.')
163
164 if not sys.stdin.isatty():
165 # Issue 14853: stdin becomes seekable when redirected to a file
166 self.skipTest('stdin must be a TTY in this test')
167
168 with self.assertRaises((IOError, ValueError)):
169 sys.stdin.seek(-1)
170 with self.assertRaises((IOError, ValueError)):
171 sys.stdin.truncate()
172
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000173 def testBadModeArgument(self):
174 # verify that we get a sensible error message for bad mode argument
175 bad_mode = "qwerty"
Tim Peterscffcfed2006-02-14 17:41:18 +0000176 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000177 f = self.open(TESTFN, bad_mode)
Guido van Rossumb940e112007-01-10 16:19:56 +0000178 except ValueError as msg:
Brett Cannonca477b22007-03-21 22:26:20 +0000179 if msg.args[0] != 0:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000180 s = str(msg)
Ezio Melotti7fb4da72010-03-18 12:29:13 +0000181 if TESTFN in s or bad_mode not in s:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000182 self.fail("bad error message for invalid mode: %s" % s)
Georg Brandl50da60c2008-01-06 21:38:54 +0000183 # if msg.args[0] == 0, we're probably on Windows where there may be
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000184 # no obvious way to discover why open() failed.
185 else:
186 f.close()
187 self.fail("no error for invalid mode: %s" % bad_mode)
188
Alexey Izbysheva2670562018-10-20 03:22:31 +0300189 def _checkBufferSize(self, s):
190 try:
191 f = self.open(TESTFN, 'wb', s)
192 f.write(str(s).encode("ascii"))
193 f.close()
194 f.close()
195 f = self.open(TESTFN, 'rb', s)
196 d = int(f.read().decode("ascii"))
197 f.close()
198 f.close()
199 except OSError as msg:
200 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
201 self.assertEqual(d, s)
202
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000203 def testSetBufferSize(self):
204 # make sure that explicitly setting the buffer size doesn't cause
205 # misbehaviour especially with repeated close() calls
Alexey Izbysheva2670562018-10-20 03:22:31 +0300206 for s in (-1, 0, 512):
Hai Shia089d212020-07-06 17:15:08 +0800207 with warnings_helper.check_no_warnings(self,
Alexey Izbysheva2670562018-10-20 03:22:31 +0300208 message='line buffering',
209 category=RuntimeWarning):
210 self._checkBufferSize(s)
211
212 # test that attempts to use line buffering in binary mode cause
213 # a warning
214 with self.assertWarnsRegex(RuntimeWarning, 'line buffering'):
215 self._checkBufferSize(1)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000216
217 def testTruncateOnWindows(self):
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000218 # SF bug <http://www.python.org/sf/801631>
219 # "file.truncate fault on windows"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000220
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000221 f = self.open(TESTFN, 'wb')
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000222
223 try:
Guido van Rossum7165cb12007-07-10 06:54:34 +0000224 f.write(b'12345678901') # 11 bytes
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000225 f.close()
226
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000227 f = self.open(TESTFN,'rb+')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000228 data = f.read(5)
Guido van Rossum7165cb12007-07-10 06:54:34 +0000229 if data != b'12345':
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000230 self.fail("Read on file opened for update failed %r" % data)
231 if f.tell() != 5:
232 self.fail("File pos after read wrong %d" % f.tell())
233
234 f.truncate()
235 if f.tell() != 5:
236 self.fail("File pos after ftruncate wrong %d" % f.tell())
237
238 f.close()
239 size = os.path.getsize(TESTFN)
240 if size != 5:
241 self.fail("File size after ftruncate wrong %d" % size)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000242 finally:
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000243 f.close()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000244
245 def testIteration(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000246 # Test the complex interaction when mixing file-iteration and the
Guido van Rossum7165cb12007-07-10 06:54:34 +0000247 # various read* methods.
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000248 dataoffset = 16384
Guido van Rossume22905a2007-08-27 23:09:25 +0000249 filler = b"ham\n"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000250 assert not dataoffset % len(filler), \
251 "dataoffset must be multiple of len(filler)"
252 nchunks = dataoffset // len(filler)
253 testlines = [
Guido van Rossum7165cb12007-07-10 06:54:34 +0000254 b"spam, spam and eggs\n",
255 b"eggs, spam, ham and spam\n",
256 b"saussages, spam, spam and eggs\n",
257 b"spam, ham, spam and eggs\n",
258 b"spam, spam, spam, spam, spam, ham, spam\n",
259 b"wonderful spaaaaaam.\n"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000260 ]
261 methods = [("readline", ()), ("read", ()), ("readlines", ()),
Guido van Rossum7165cb12007-07-10 06:54:34 +0000262 ("readinto", (array("b", b" "*100),))]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000263
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300264 # Prepare the testfile
265 bag = self.open(TESTFN, "wb")
266 bag.write(filler * nchunks)
267 bag.writelines(testlines)
268 bag.close()
269 # Test for appropriate errors mixing read* and iteration
270 for methodname, args in methods:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000271 f = self.open(TESTFN, 'rb')
Bradley Laney6b490b52018-07-10 05:46:44 -0400272 self.assertEqual(next(f), filler)
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300273 meth = getattr(f, methodname)
274 meth(*args) # This simply shouldn't fail
Antoine Pitroua6e95022010-10-30 14:22:43 +0000275 f.close()
276
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300277 # Test to see if harmless (by accident) mixing of read* and
278 # iteration still works. This depends on the size of the internal
279 # iteration buffer (currently 8192,) but we can test it in a
280 # flexible manner. Each line in the bag o' ham is 4 bytes
281 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
282 # exactly on the buffer boundary for any power-of-2 buffersize
283 # between 4 and 16384 (inclusive).
284 f = self.open(TESTFN, 'rb')
285 for i in range(nchunks):
286 next(f)
287 testline = testlines.pop(0)
288 try:
289 line = f.readline()
290 except ValueError:
291 self.fail("readline() after next() with supposedly empty "
292 "iteration-buffer failed anyway")
293 if line != testline:
294 self.fail("readline() after next() with empty buffer "
295 "failed. Got %r, expected %r" % (line, testline))
296 testline = testlines.pop(0)
297 buf = array("b", b"\x00" * len(testline))
298 try:
299 f.readinto(buf)
300 except ValueError:
301 self.fail("readinto() after next() with supposedly empty "
302 "iteration-buffer failed anyway")
303 line = buf.tobytes()
304 if line != testline:
305 self.fail("readinto() after next() with empty buffer "
306 "failed. Got %r, expected %r" % (line, testline))
307
308 testline = testlines.pop(0)
309 try:
310 line = f.read(len(testline))
311 except ValueError:
312 self.fail("read() after next() with supposedly empty "
313 "iteration-buffer failed anyway")
314 if line != testline:
315 self.fail("read() after next() with empty buffer "
316 "failed. Got %r, expected %r" % (line, testline))
317 try:
318 lines = f.readlines()
319 except ValueError:
320 self.fail("readlines() after next() with supposedly empty "
321 "iteration-buffer failed anyway")
322 if lines != testlines:
323 self.fail("readlines() after next() with empty buffer "
324 "failed. Got %r, expected %r" % (line, testline))
325 f.close()
326
327 # Reading after iteration hit EOF shouldn't hurt either
328 f = self.open(TESTFN, 'rb')
329 try:
330 for line in f:
331 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000332 try:
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300333 f.readline()
334 f.readinto(buf)
335 f.read()
336 f.readlines()
337 except ValueError:
338 self.fail("read* failed after next() consumed file")
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000339 finally:
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300340 f.close()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000341
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200342class COtherFileTests(OtherFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000343 open = io.open
344
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200345class PyOtherFileTests(OtherFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000346 open = staticmethod(pyio.open)
347
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000348
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000349if __name__ == '__main__':
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200350 unittest.main()