blob: cd642e7aaf8bb8634a14f751c924585369b355bc [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
Serhiy Storchaka597d15a2016-04-24 13:45:58 +030010from test.support import TESTFN
Serhiy Storchakac2745d22018-06-05 19:55:41 +030011from test import support
Raymond Hettinger53dbe392008-02-12 20:03:09 +000012from collections import UserList
Marc-André Lemburgfa44d792000-08-25 22:37:31 +000013
Ezio Melotti3a03d2e2013-02-15 19:17:53 +020014class AutoFileTests:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000015 # file tests for which a test file is automatically set up
Raymond Hettingercb87bc82004-05-31 00:35:52 +000016
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000017 def setUp(self):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000018 self.f = self.open(TESTFN, 'wb')
Tim Peters015dd822003-05-04 04:16:52 +000019
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000020 def tearDown(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000021 if self.f:
22 self.f.close()
Serhiy Storchakac2745d22018-06-05 19:55:41 +030023 support.unlink(TESTFN)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000024
25 def testWeakRefs(self):
26 # verify weak references
27 p = proxy(self.f)
Guido van Rossume22905a2007-08-27 23:09:25 +000028 p.write(b'teststring')
Ezio Melottib3aedd42010-11-20 19:04:17 +000029 self.assertEqual(self.f.tell(), p.tell())
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000030 self.f.close()
31 self.f = None
32 self.assertRaises(ReferenceError, getattr, p, 'tell')
33
34 def testAttributes(self):
35 # verify expected attributes exist
36 f = self.f
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000037 f.name # merely shouldn't blow up
38 f.mode # ditto
39 f.closed # ditto
40
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000041 def testReadinto(self):
42 # verify readinto
Guido van Rossume22905a2007-08-27 23:09:25 +000043 self.f.write(b'12')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000044 self.f.close()
Guido van Rossum7165cb12007-07-10 06:54:34 +000045 a = array('b', b'x'*10)
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000046 self.f = self.open(TESTFN, 'rb')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000047 n = self.f.readinto(a)
Ezio Melottib3aedd42010-11-20 19:04:17 +000048 self.assertEqual(b'12', a.tobytes()[:n])
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000049
50 def testReadinto_text(self):
51 # verify readinto refuses text files
Guido van Rossum7165cb12007-07-10 06:54:34 +000052 a = array('b', b'x'*10)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000053 self.f.close()
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000054 self.f = self.open(TESTFN, 'r')
Guido van Rossum7165cb12007-07-10 06:54:34 +000055 if hasattr(self.f, "readinto"):
56 self.assertRaises(TypeError, self.f.readinto, a)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000057
58 def testWritelinesUserList(self):
59 # verify writelines with instance sequence
Guido van Rossum7165cb12007-07-10 06:54:34 +000060 l = UserList([b'1', b'2'])
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000061 self.f.writelines(l)
62 self.f.close()
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000063 self.f = self.open(TESTFN, 'rb')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000064 buf = self.f.read()
Ezio Melottib3aedd42010-11-20 19:04:17 +000065 self.assertEqual(buf, b'12')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000066
67 def testWritelinesIntegers(self):
68 # verify writelines with integers
69 self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
70
71 def testWritelinesIntegersUserList(self):
72 # verify writelines with integers in UserList
73 l = UserList([1,2,3])
74 self.assertRaises(TypeError, self.f.writelines, l)
75
76 def testWritelinesNonString(self):
77 # verify writelines with non-string object
Thomas Wouters0e3f5912006-08-11 14:57:12 +000078 class NonString:
79 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000080
Thomas Wouters0e3f5912006-08-11 14:57:12 +000081 self.assertRaises(TypeError, self.f.writelines,
82 [NonString(), NonString()])
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000083
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000084 def testErrors(self):
85 f = self.f
Ezio Melottib3aedd42010-11-20 19:04:17 +000086 self.assertEqual(f.name, TESTFN)
Serhiy Storchaka0dcd80a2015-08-02 15:17:49 +030087 self.assertFalse(f.isatty())
88 self.assertFalse(f.closed)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000089
Guido van Rossum7165cb12007-07-10 06:54:34 +000090 if hasattr(f, "readinto"):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +020091 self.assertRaises((OSError, TypeError), f.readinto, "")
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000092 f.close()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000093 self.assertTrue(f.closed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000094
95 def testMethods(self):
Guido van Rossum4b5386f2007-07-10 09:12:49 +000096 methods = [('fileno', ()),
97 ('flush', ()),
98 ('isatty', ()),
99 ('__next__', ()),
100 ('read', ()),
101 ('write', (b"",)),
102 ('readline', ()),
103 ('readlines', ()),
104 ('seek', (0,)),
105 ('tell', ()),
106 ('write', (b"",)),
107 ('writelines', ([],)),
108 ('__iter__', ()),
109 ]
Antoine Pitrou6103ab12009-10-24 20:11:21 +0000110 methods.append(('truncate', ()))
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000111
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000112 # __exit__ should close the file
113 self.f.__exit__(None, None, None)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000114 self.assertTrue(self.f.closed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000115
Guido van Rossum4b5386f2007-07-10 09:12:49 +0000116 for methodname, args in methods:
117 method = getattr(self.f, methodname)
118 # should raise on closed file
119 self.assertRaises(ValueError, method, *args)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000120
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000121 # file is closed, __exit__ shouldn't do anything
Ezio Melottib3aedd42010-11-20 19:04:17 +0000122 self.assertEqual(self.f.__exit__(None, None, None), None)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000123 # it must also return None if an exception was given
124 try:
125 1/0
126 except:
Ezio Melottib3aedd42010-11-20 19:04:17 +0000127 self.assertEqual(self.f.__exit__(*sys.exc_info()), None)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000128
Skip Montanaro80072cb2008-12-23 03:51:14 +0000129 def testReadWhenWriting(self):
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200130 self.assertRaises(OSError, self.f.read)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000131
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200132class CAutoFileTests(AutoFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000133 open = io.open
134
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200135class PyAutoFileTests(AutoFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000136 open = staticmethod(pyio.open)
137
138
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200139class OtherFileTests:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000140
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300141 def tearDown(self):
142 support.unlink(TESTFN)
143
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000144 def testModeStrings(self):
145 # check invalid mode strings
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300146 self.open(TESTFN, 'wb').close()
Robert Collinsc94a1dc2015-07-26 06:43:13 +1200147 for mode in ("", "aU", "wU+", "U+", "+U", "rU+"):
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000148 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000149 f = self.open(TESTFN, mode)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000150 except ValueError:
151 pass
152 else:
153 f.close()
154 self.fail('%r is an invalid file mode' % mode)
155
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000156 def testBadModeArgument(self):
157 # verify that we get a sensible error message for bad mode argument
158 bad_mode = "qwerty"
Tim Peterscffcfed2006-02-14 17:41:18 +0000159 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000160 f = self.open(TESTFN, bad_mode)
Guido van Rossumb940e112007-01-10 16:19:56 +0000161 except ValueError as msg:
Brett Cannonca477b22007-03-21 22:26:20 +0000162 if msg.args[0] != 0:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000163 s = str(msg)
Ezio Melotti7fb4da72010-03-18 12:29:13 +0000164 if TESTFN in s or bad_mode not in s:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000165 self.fail("bad error message for invalid mode: %s" % s)
Georg Brandl50da60c2008-01-06 21:38:54 +0000166 # if msg.args[0] == 0, we're probably on Windows where there may be
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000167 # no obvious way to discover why open() failed.
168 else:
169 f.close()
170 self.fail("no error for invalid mode: %s" % bad_mode)
171
Alexey Izbysheva2670562018-10-20 03:22:31 +0300172 def _checkBufferSize(self, s):
173 try:
174 f = self.open(TESTFN, 'wb', s)
175 f.write(str(s).encode("ascii"))
176 f.close()
177 f.close()
178 f = self.open(TESTFN, 'rb', s)
179 d = int(f.read().decode("ascii"))
180 f.close()
181 f.close()
182 except OSError as msg:
183 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
184 self.assertEqual(d, s)
185
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000186 def testSetBufferSize(self):
187 # make sure that explicitly setting the buffer size doesn't cause
188 # misbehaviour especially with repeated close() calls
Alexey Izbysheva2670562018-10-20 03:22:31 +0300189 for s in (-1, 0, 512):
190 with support.check_no_warnings(self,
191 message='line buffering',
192 category=RuntimeWarning):
193 self._checkBufferSize(s)
194
195 # test that attempts to use line buffering in binary mode cause
196 # a warning
197 with self.assertWarnsRegex(RuntimeWarning, 'line buffering'):
198 self._checkBufferSize(1)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000199
200 def testTruncateOnWindows(self):
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000201 # SF bug <http://www.python.org/sf/801631>
202 # "file.truncate fault on windows"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000203
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000204 f = self.open(TESTFN, 'wb')
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000205
206 try:
Guido van Rossum7165cb12007-07-10 06:54:34 +0000207 f.write(b'12345678901') # 11 bytes
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000208 f.close()
209
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000210 f = self.open(TESTFN,'rb+')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000211 data = f.read(5)
Guido van Rossum7165cb12007-07-10 06:54:34 +0000212 if data != b'12345':
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000213 self.fail("Read on file opened for update failed %r" % data)
214 if f.tell() != 5:
215 self.fail("File pos after read wrong %d" % f.tell())
216
217 f.truncate()
218 if f.tell() != 5:
219 self.fail("File pos after ftruncate wrong %d" % f.tell())
220
221 f.close()
222 size = os.path.getsize(TESTFN)
223 if size != 5:
224 self.fail("File size after ftruncate wrong %d" % size)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000225 finally:
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000226 f.close()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000227
228 def testIteration(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000229 # Test the complex interaction when mixing file-iteration and the
Guido van Rossum7165cb12007-07-10 06:54:34 +0000230 # various read* methods.
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000231 dataoffset = 16384
Guido van Rossume22905a2007-08-27 23:09:25 +0000232 filler = b"ham\n"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000233 assert not dataoffset % len(filler), \
234 "dataoffset must be multiple of len(filler)"
235 nchunks = dataoffset // len(filler)
236 testlines = [
Guido van Rossum7165cb12007-07-10 06:54:34 +0000237 b"spam, spam and eggs\n",
238 b"eggs, spam, ham and spam\n",
239 b"saussages, spam, spam and eggs\n",
240 b"spam, ham, spam and eggs\n",
241 b"spam, spam, spam, spam, spam, ham, spam\n",
242 b"wonderful spaaaaaam.\n"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000243 ]
244 methods = [("readline", ()), ("read", ()), ("readlines", ()),
Guido van Rossum7165cb12007-07-10 06:54:34 +0000245 ("readinto", (array("b", b" "*100),))]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000246
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300247 # Prepare the testfile
248 bag = self.open(TESTFN, "wb")
249 bag.write(filler * nchunks)
250 bag.writelines(testlines)
251 bag.close()
252 # Test for appropriate errors mixing read* and iteration
253 for methodname, args in methods:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000254 f = self.open(TESTFN, 'rb')
Bradley Laney6b490b52018-07-10 05:46:44 -0400255 self.assertEqual(next(f), filler)
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300256 meth = getattr(f, methodname)
257 meth(*args) # This simply shouldn't fail
Antoine Pitroua6e95022010-10-30 14:22:43 +0000258 f.close()
259
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300260 # Test to see if harmless (by accident) mixing of read* and
261 # iteration still works. This depends on the size of the internal
262 # iteration buffer (currently 8192,) but we can test it in a
263 # flexible manner. Each line in the bag o' ham is 4 bytes
264 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
265 # exactly on the buffer boundary for any power-of-2 buffersize
266 # between 4 and 16384 (inclusive).
267 f = self.open(TESTFN, 'rb')
268 for i in range(nchunks):
269 next(f)
270 testline = testlines.pop(0)
271 try:
272 line = f.readline()
273 except ValueError:
274 self.fail("readline() after next() with supposedly empty "
275 "iteration-buffer failed anyway")
276 if line != testline:
277 self.fail("readline() after next() with empty buffer "
278 "failed. Got %r, expected %r" % (line, testline))
279 testline = testlines.pop(0)
280 buf = array("b", b"\x00" * len(testline))
281 try:
282 f.readinto(buf)
283 except ValueError:
284 self.fail("readinto() after next() with supposedly empty "
285 "iteration-buffer failed anyway")
286 line = buf.tobytes()
287 if line != testline:
288 self.fail("readinto() after next() with empty buffer "
289 "failed. Got %r, expected %r" % (line, testline))
290
291 testline = testlines.pop(0)
292 try:
293 line = f.read(len(testline))
294 except ValueError:
295 self.fail("read() after next() with supposedly empty "
296 "iteration-buffer failed anyway")
297 if line != testline:
298 self.fail("read() after next() with empty buffer "
299 "failed. Got %r, expected %r" % (line, testline))
300 try:
301 lines = f.readlines()
302 except ValueError:
303 self.fail("readlines() after next() with supposedly empty "
304 "iteration-buffer failed anyway")
305 if lines != testlines:
306 self.fail("readlines() after next() with empty buffer "
307 "failed. Got %r, expected %r" % (line, testline))
308 f.close()
309
310 # Reading after iteration hit EOF shouldn't hurt either
311 f = self.open(TESTFN, 'rb')
312 try:
313 for line in f:
314 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000315 try:
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300316 f.readline()
317 f.readinto(buf)
318 f.read()
319 f.readlines()
320 except ValueError:
321 self.fail("read* failed after next() consumed file")
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000322 finally:
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300323 f.close()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000324
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200325class COtherFileTests(OtherFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000326 open = io.open
327
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200328class PyOtherFileTests(OtherFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000329 open = staticmethod(pyio.open)
330
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000331
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000332if __name__ == '__main__':
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200333 unittest.main()