blob: f58d1dae6045f49ff17ae8a852ed6ab8371f92b0 [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
172 def testSetBufferSize(self):
173 # make sure that explicitly setting the buffer size doesn't cause
174 # misbehaviour especially with repeated close() calls
175 for s in (-1, 0, 1, 512):
176 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000177 f = self.open(TESTFN, 'wb', s)
Guido van Rossum7165cb12007-07-10 06:54:34 +0000178 f.write(str(s).encode("ascii"))
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000179 f.close()
180 f.close()
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000181 f = self.open(TESTFN, 'rb', s)
Guido van Rossum7165cb12007-07-10 06:54:34 +0000182 d = int(f.read().decode("ascii"))
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000183 f.close()
184 f.close()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200185 except OSError as msg:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000186 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000187 self.assertEqual(d, s)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000188
189 def testTruncateOnWindows(self):
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000190 # SF bug <http://www.python.org/sf/801631>
191 # "file.truncate fault on windows"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000192
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000193 f = self.open(TESTFN, 'wb')
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000194
195 try:
Guido van Rossum7165cb12007-07-10 06:54:34 +0000196 f.write(b'12345678901') # 11 bytes
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000197 f.close()
198
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000199 f = self.open(TESTFN,'rb+')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000200 data = f.read(5)
Guido van Rossum7165cb12007-07-10 06:54:34 +0000201 if data != b'12345':
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000202 self.fail("Read on file opened for update failed %r" % data)
203 if f.tell() != 5:
204 self.fail("File pos after read wrong %d" % f.tell())
205
206 f.truncate()
207 if f.tell() != 5:
208 self.fail("File pos after ftruncate wrong %d" % f.tell())
209
210 f.close()
211 size = os.path.getsize(TESTFN)
212 if size != 5:
213 self.fail("File size after ftruncate wrong %d" % size)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000214 finally:
Guido van Rossum79b79ee2007-10-25 23:21:03 +0000215 f.close()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000216
217 def testIteration(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000218 # Test the complex interaction when mixing file-iteration and the
Guido van Rossum7165cb12007-07-10 06:54:34 +0000219 # various read* methods.
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000220 dataoffset = 16384
Guido van Rossume22905a2007-08-27 23:09:25 +0000221 filler = b"ham\n"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000222 assert not dataoffset % len(filler), \
223 "dataoffset must be multiple of len(filler)"
224 nchunks = dataoffset // len(filler)
225 testlines = [
Guido van Rossum7165cb12007-07-10 06:54:34 +0000226 b"spam, spam and eggs\n",
227 b"eggs, spam, ham and spam\n",
228 b"saussages, spam, spam and eggs\n",
229 b"spam, ham, spam and eggs\n",
230 b"spam, spam, spam, spam, spam, ham, spam\n",
231 b"wonderful spaaaaaam.\n"
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000232 ]
233 methods = [("readline", ()), ("read", ()), ("readlines", ()),
Guido van Rossum7165cb12007-07-10 06:54:34 +0000234 ("readinto", (array("b", b" "*100),))]
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000235
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300236 # Prepare the testfile
237 bag = self.open(TESTFN, "wb")
238 bag.write(filler * nchunks)
239 bag.writelines(testlines)
240 bag.close()
241 # Test for appropriate errors mixing read* and iteration
242 for methodname, args in methods:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000243 f = self.open(TESTFN, 'rb')
Bradley Laney6b490b52018-07-10 05:46:44 -0400244 self.assertEqual(next(f), filler)
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300245 meth = getattr(f, methodname)
246 meth(*args) # This simply shouldn't fail
Antoine Pitroua6e95022010-10-30 14:22:43 +0000247 f.close()
248
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300249 # Test to see if harmless (by accident) mixing of read* and
250 # iteration still works. This depends on the size of the internal
251 # iteration buffer (currently 8192,) but we can test it in a
252 # flexible manner. Each line in the bag o' ham is 4 bytes
253 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
254 # exactly on the buffer boundary for any power-of-2 buffersize
255 # between 4 and 16384 (inclusive).
256 f = self.open(TESTFN, 'rb')
257 for i in range(nchunks):
258 next(f)
259 testline = testlines.pop(0)
260 try:
261 line = f.readline()
262 except ValueError:
263 self.fail("readline() after next() with supposedly empty "
264 "iteration-buffer failed anyway")
265 if line != testline:
266 self.fail("readline() after next() with empty buffer "
267 "failed. Got %r, expected %r" % (line, testline))
268 testline = testlines.pop(0)
269 buf = array("b", b"\x00" * len(testline))
270 try:
271 f.readinto(buf)
272 except ValueError:
273 self.fail("readinto() after next() with supposedly empty "
274 "iteration-buffer failed anyway")
275 line = buf.tobytes()
276 if line != testline:
277 self.fail("readinto() after next() with empty buffer "
278 "failed. Got %r, expected %r" % (line, testline))
279
280 testline = testlines.pop(0)
281 try:
282 line = f.read(len(testline))
283 except ValueError:
284 self.fail("read() after next() with supposedly empty "
285 "iteration-buffer failed anyway")
286 if line != testline:
287 self.fail("read() after next() with empty buffer "
288 "failed. Got %r, expected %r" % (line, testline))
289 try:
290 lines = f.readlines()
291 except ValueError:
292 self.fail("readlines() after next() with supposedly empty "
293 "iteration-buffer failed anyway")
294 if lines != testlines:
295 self.fail("readlines() after next() with empty buffer "
296 "failed. Got %r, expected %r" % (line, testline))
297 f.close()
298
299 # Reading after iteration hit EOF shouldn't hurt either
300 f = self.open(TESTFN, 'rb')
301 try:
302 for line in f:
303 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000304 try:
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300305 f.readline()
306 f.readinto(buf)
307 f.read()
308 f.readlines()
309 except ValueError:
310 self.fail("read* failed after next() consumed file")
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000311 finally:
Serhiy Storchakac2745d22018-06-05 19:55:41 +0300312 f.close()
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000313
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200314class COtherFileTests(OtherFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000315 open = io.open
316
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200317class PyOtherFileTests(OtherFileTests, unittest.TestCase):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000318 open = staticmethod(pyio.open)
319
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000320
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000321if __name__ == '__main__':
Ezio Melotti3a03d2e2013-02-15 19:17:53 +0200322 unittest.main()