blob: 149767591d9eb55538740746f4d800fcdc4000c7 [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()
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000055 self.f = self.open(TESTFN, 'r')
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
Thomas Wouters73e5a5b2006-06-08 15:35:45 +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:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000161 f = self.open(TESTFN, bad_mode)
Guido van Rossumb940e112007-01-10 16:19:56 +0000162 except ValueError as msg:
Brett Cannonca477b22007-03-21 22:26:20 +0000163 if msg.args[0] != 0:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000164 s = str(msg)
Ezio Melotti7fb4da72010-03-18 12:29:13 +0000165 if TESTFN in s or bad_mode not in s:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000166 self.fail("bad error message for invalid mode: %s" % s)
Georg Brandl50da60c2008-01-06 21:38:54 +0000167 # if msg.args[0] == 0, we're probably on Windows where there may be
Thomas Wouters73e5a5b2006-06-08 15:35:45 +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
Alexey Izbysheva2670562018-10-20 03:22:31 +0300173 def _checkBufferSize(self, s):
174 try:
175 f = self.open(TESTFN, 'wb', s)
176 f.write(str(s).encode("ascii"))
177 f.close()
178 f.close()
179 f = self.open(TESTFN, 'rb', s)
180 d = int(f.read().decode("ascii"))
181 f.close()
182 f.close()
183 except OSError as msg:
184 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
185 self.assertEqual(d, s)
186
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000187 def testSetBufferSize(self):
188 # make sure that explicitly setting the buffer size doesn't cause
189 # misbehaviour especially with repeated close() calls
Alexey Izbysheva2670562018-10-20 03:22:31 +0300190 for s in (-1, 0, 512):
Hai Shia089d212020-07-06 17:15:08 +0800191 with warnings_helper.check_no_warnings(self,
Alexey Izbysheva2670562018-10-20 03:22:31 +0300192 message='line buffering',
193 category=RuntimeWarning):
194 self._checkBufferSize(s)
195
196 # test that attempts to use line buffering in binary mode cause
197 # a warning
198 with self.assertWarnsRegex(RuntimeWarning, 'line buffering'):
199 self._checkBufferSize(1)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000200
201 def testTruncateOnWindows(self):
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000202 # SF bug <http://www.python.org/sf/801631>
203 # "file.truncate fault on windows"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000204
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000205 f = self.open(TESTFN, 'wb')
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000206
207 try:
Guido van Rossum7165cb12007-07-10 06:54:34 +0000208 f.write(b'12345678901') # 11 bytes
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000209 f.close()
210
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000211 f = self.open(TESTFN,'rb+')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000212 data = f.read(5)
Guido van Rossum7165cb12007-07-10 06:54:34 +0000213 if data != b'12345':
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000214 self.fail("Read on file opened for update failed %r" % data)
215 if f.tell() != 5:
216 self.fail("File pos after read wrong %d" % f.tell())
217
218 f.truncate()
219 if f.tell() != 5:
220 self.fail("File pos after ftruncate wrong %d" % f.tell())
221
222 f.close()
223 size = os.path.getsize(TESTFN)
224 if size != 5:
225 self.fail("File size after ftruncate wrong %d" % size)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000226 finally:
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000227 f.close()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000228
229 def testIteration(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000230 # Test the complex interaction when mixing file-iteration and the
Guido van Rossum7165cb12007-07-10 06:54:34 +0000231 # various read* methods.
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000232 dataoffset = 16384
Guido van Rossume22905a2007-08-27 23:09:25 +0000233 filler = b"ham\n"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000234 assert not dataoffset % len(filler), \
235 "dataoffset must be multiple of len(filler)"
236 nchunks = dataoffset // len(filler)
237 testlines = [
Guido van Rossum7165cb12007-07-10 06:54:34 +0000238 b"spam, spam and eggs\n",
239 b"eggs, spam, ham and spam\n",
240 b"saussages, spam, spam and eggs\n",
241 b"spam, ham, spam and eggs\n",
242 b"spam, spam, spam, spam, spam, ham, spam\n",
243 b"wonderful spaaaaaam.\n"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000244 ]
245 methods = [("readline", ()), ("read", ()), ("readlines", ()),
Guido van Rossum7165cb12007-07-10 06:54:34 +0000246 ("readinto", (array("b", b" "*100),))]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000247
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300248 # Prepare the testfile
249 bag = self.open(TESTFN, "wb")
250 bag.write(filler * nchunks)
251 bag.writelines(testlines)
252 bag.close()
253 # Test for appropriate errors mixing read* and iteration
254 for methodname, args in methods:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000255 f = self.open(TESTFN, 'rb')
Bradley Laney6b490b52018-07-10 05:46:44 -0400256 self.assertEqual(next(f), filler)
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300257 meth = getattr(f, methodname)
258 meth(*args) # This simply shouldn't fail
Antoine Pitroua6e95022010-10-30 14:22:43 +0000259 f.close()
260
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300261 # Test to see if harmless (by accident) mixing of read* and
262 # iteration still works. This depends on the size of the internal
263 # iteration buffer (currently 8192,) but we can test it in a
264 # flexible manner. Each line in the bag o' ham is 4 bytes
265 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
266 # exactly on the buffer boundary for any power-of-2 buffersize
267 # between 4 and 16384 (inclusive).
268 f = self.open(TESTFN, 'rb')
269 for i in range(nchunks):
270 next(f)
271 testline = testlines.pop(0)
272 try:
273 line = f.readline()
274 except ValueError:
275 self.fail("readline() after next() with supposedly empty "
276 "iteration-buffer failed anyway")
277 if line != testline:
278 self.fail("readline() after next() with empty buffer "
279 "failed. Got %r, expected %r" % (line, testline))
280 testline = testlines.pop(0)
281 buf = array("b", b"\x00" * len(testline))
282 try:
283 f.readinto(buf)
284 except ValueError:
285 self.fail("readinto() after next() with supposedly empty "
286 "iteration-buffer failed anyway")
287 line = buf.tobytes()
288 if line != testline:
289 self.fail("readinto() after next() with empty buffer "
290 "failed. Got %r, expected %r" % (line, testline))
291
292 testline = testlines.pop(0)
293 try:
294 line = f.read(len(testline))
295 except ValueError:
296 self.fail("read() after next() with supposedly empty "
297 "iteration-buffer failed anyway")
298 if line != testline:
299 self.fail("read() after next() with empty buffer "
300 "failed. Got %r, expected %r" % (line, testline))
301 try:
302 lines = f.readlines()
303 except ValueError:
304 self.fail("readlines() after next() with supposedly empty "
305 "iteration-buffer failed anyway")
306 if lines != testlines:
307 self.fail("readlines() after next() with empty buffer "
308 "failed. Got %r, expected %r" % (line, testline))
309 f.close()
310
311 # Reading after iteration hit EOF shouldn't hurt either
312 f = self.open(TESTFN, 'rb')
313 try:
314 for line in f:
315 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000316 try:
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300317 f.readline()
318 f.readinto(buf)
319 f.read()
320 f.readlines()
321 except ValueError:
322 self.fail("read* failed after next() consumed file")
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000323 finally:
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300324 f.close()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000325
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200326class COtherFileTests(OtherFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000327 open = io.open
328
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200329class PyOtherFileTests(OtherFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000330 open = staticmethod(pyio.open)
331
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000332
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000333if __name__ == '__main__':
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200334 unittest.main()