blob: 9188e70e30af5900b4b00747d706b5d2e2475634 [file] [log] [blame]
Guido van Rossumde3bc7c2007-03-08 01:02:00 +00001# Adapted from test_file.py by Daniel Stutzbach
Guido van Rossuma9e20242007-03-08 00:43:48 +00002
3import sys
4import os
Antoine Pitrou0ae29cf2009-03-13 22:33:17 +00005import errno
Guido van Rossuma9e20242007-03-08 00:43:48 +00006import unittest
7from array import array
8from weakref import proxy
Kristján Valur Jónssona8abe862009-03-24 15:27:42 +00009from functools import wraps
Guido van Rossuma9e20242007-03-08 00:43:48 +000010
Benjamin Peterson7522c742009-01-19 21:00:09 +000011from test.support import (TESTFN, findfile, check_warnings, run_unittest,
12 make_bad_fd)
Raymond Hettinger53dbe392008-02-12 20:03:09 +000013from collections import UserList
Guido van Rossuma9e20242007-03-08 00:43:48 +000014
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000015from _io import FileIO as _FileIO
Guido van Rossuma9e20242007-03-08 00:43:48 +000016
17class AutoFileTests(unittest.TestCase):
18 # file tests for which a test file is automatically set up
19
20 def setUp(self):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000021 self.f = _FileIO(TESTFN, 'w')
Guido van Rossuma9e20242007-03-08 00:43:48 +000022
23 def tearDown(self):
24 if self.f:
25 self.f.close()
26 os.remove(TESTFN)
27
28 def testWeakRefs(self):
29 # verify weak references
30 p = proxy(self.f)
31 p.write(bytes(range(10)))
32 self.assertEquals(self.f.tell(), p.tell())
33 self.f.close()
34 self.f = None
35 self.assertRaises(ReferenceError, getattr, p, 'tell')
36
37 def testSeekTell(self):
38 self.f.write(bytes(range(20)))
39 self.assertEquals(self.f.tell(), 20)
40 self.f.seek(0)
41 self.assertEquals(self.f.tell(), 0)
42 self.f.seek(10)
43 self.assertEquals(self.f.tell(), 10)
44 self.f.seek(5, 1)
45 self.assertEquals(self.f.tell(), 15)
46 self.f.seek(-5, 1)
47 self.assertEquals(self.f.tell(), 10)
48 self.f.seek(-5, 2)
49 self.assertEquals(self.f.tell(), 15)
50
51 def testAttributes(self):
52 # verify expected attributes exist
53 f = self.f
Guido van Rossuma9e20242007-03-08 00:43:48 +000054
Benjamin Peterson44309e62008-11-22 00:41:45 +000055 self.assertEquals(f.mode, "wb")
Guido van Rossum31c3a572007-04-12 14:51:49 +000056 self.assertEquals(f.closed, False)
57
58 # verify the attributes are readonly
59 for attr in 'mode', 'closed':
60 self.assertRaises((AttributeError, TypeError),
61 setattr, f, attr, 'oops')
Guido van Rossuma9e20242007-03-08 00:43:48 +000062
63 def testReadinto(self):
64 # verify readinto
65 self.f.write(bytes([1, 2]))
66 self.f.close()
Guido van Rossuma45ea582007-05-15 21:25:12 +000067 a = array('b', b'x'*10)
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000068 self.f = _FileIO(TESTFN, 'r')
Guido van Rossuma9e20242007-03-08 00:43:48 +000069 n = self.f.readinto(a)
70 self.assertEquals(array('b', [1, 2]), a[:n])
71
72 def testRepr(self):
Guido van Rossum682faf82007-04-12 14:56:58 +000073 self.assertEquals(repr(self.f),
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000074 "io.FileIO(%d, %s)" % (self.f.fileno(),
Guido van Rossum682faf82007-04-12 14:56:58 +000075 repr(self.f.mode)))
Guido van Rossuma9e20242007-03-08 00:43:48 +000076
77 def testErrors(self):
78 f = self.f
79 self.assert_(not f.isatty())
Guido van Rossum31c3a572007-04-12 14:51:49 +000080 self.assert_(not f.closed)
Guido van Rossuma9e20242007-03-08 00:43:48 +000081 #self.assertEquals(f.name, TESTFN)
Guido van Rossum31c3a572007-04-12 14:51:49 +000082 self.assertRaises(ValueError, f.read, 10) # Open for reading
Guido van Rossuma9e20242007-03-08 00:43:48 +000083 f.close()
Guido van Rossum31c3a572007-04-12 14:51:49 +000084 self.assert_(f.closed)
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +000085 f = _FileIO(TESTFN, 'r')
Guido van Rossum31c3a572007-04-12 14:51:49 +000086 self.assertRaises(TypeError, f.readinto, "")
87 self.assert_(not f.closed)
88 f.close()
89 self.assert_(f.closed)
Guido van Rossuma9e20242007-03-08 00:43:48 +000090
91 def testMethods(self):
92 methods = ['fileno', 'isatty', 'read', 'readinto',
93 'seek', 'tell', 'truncate', 'write', 'seekable',
94 'readable', 'writable']
95 if sys.platform.startswith('atheos'):
96 methods.remove('truncate')
97
Guido van Rossum31c3a572007-04-12 14:51:49 +000098 self.f.close()
99 self.assert_(self.f.closed)
Guido van Rossuma9e20242007-03-08 00:43:48 +0000100
101 for methodname in methods:
102 method = getattr(self.f, methodname)
103 # should raise on closed file
104 self.assertRaises(ValueError, method)
105
Benjamin Peterson3e4f0552008-09-02 00:31:15 +0000106 def testOpendir(self):
107 # Issue 3703: opening a directory should fill the errno
108 # Windows always returns "[Errno 13]: Permission denied
109 # Unix calls dircheck() and returns "[Errno 21]: Is a directory"
110 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000111 _FileIO('.', 'r')
Benjamin Peterson3e4f0552008-09-02 00:31:15 +0000112 except IOError as e:
113 self.assertNotEqual(e.errno, 0)
Benjamin Peterson1efc23c2008-12-29 18:02:28 +0000114 self.assertEqual(e.filename, ".")
Benjamin Peterson3e4f0552008-09-02 00:31:15 +0000115 else:
116 self.fail("Should have raised IOError")
117
Kristján Valur Jónssona8abe862009-03-24 15:27:42 +0000118 #A set of functions testing that we get expected behaviour if someone has
119 #manually closed the internal file descriptor. First, a decorator:
120 def ClosedFD(func):
121 @wraps(func)
122 def wrapper(self):
123 #forcibly close the fd before invoking the problem function
124 f = self.f
125 os.close(f.fileno())
126 try:
127 func(self, f)
128 finally:
129 try:
130 self.f.close()
131 except IOError:
132 pass
133 return wrapper
Antoine Pitrou0ae29cf2009-03-13 22:33:17 +0000134
Kristján Valur Jónssona8abe862009-03-24 15:27:42 +0000135 def ClosedFDRaises(func):
136 @wraps(func)
137 def wrapper(self):
138 #forcibly close the fd before invoking the problem function
139 f = self.f
140 os.close(f.fileno())
141 try:
142 func(self, f)
143 except IOError as e:
144 self.assertEqual(e.errno, errno.EBADF)
145 else:
146 self.fail("Should have raised IOError")
147 finally:
148 try:
149 self.f.close()
150 except IOError:
151 pass
152 return wrapper
153
154 @ClosedFDRaises
155 def testErrnoOnClose(self, f):
156 f.close()
157
158 @ClosedFDRaises
159 def testErrnoOnClosedWrite(self, f):
160 f.write('a')
161
162 @ClosedFDRaises
163 def testErrnoOnClosedSeek(self, f):
164 f.seek(0)
165
166 @ClosedFDRaises
167 def testErrnoOnClosedTell(self, f):
168 f.tell()
169
170 @ClosedFDRaises
171 def testErrnoOnClosedTruncate(self, f):
172 f.truncate(0)
173
174 @ClosedFD
175 def testErrnoOnClosedSeekable(self, f):
176 f.seekable()
177
178 @ClosedFD
179 def testErrnoOnClosedReadable(self, f):
180 f.readable()
181
182 @ClosedFD
183 def testErrnoOnClosedWritable(self, f):
184 f.writable()
185
186 @ClosedFD
187 def testErrnoOnClosedFileno(self, f):
188 f.fileno()
189
190 @ClosedFD
191 def testErrnoOnClosedIsatty(self, f):
192 self.assertEqual(f.isatty(), False)
193
194 def ReopenForRead(self):
195 try:
196 self.f.close()
197 except IOError:
198 pass
199 self.f = _FileIO(TESTFN, 'r')
200 os.close(self.f.fileno())
201 return self.f
202
203 @ClosedFDRaises
204 def testErrnoOnClosedRead(self, f):
205 f = self.ReopenForRead()
206 f.read(1)
207
208 @ClosedFDRaises
209 def testErrnoOnClosedReadall(self, f):
210 f = self.ReopenForRead()
211 f.readall()
212
213 @ClosedFDRaises
214 def testErrnoOnClosedReadinto(self, f):
215 f = self.ReopenForRead()
216 a = array('b', b'x'*10)
217 f.readinto(a)
Guido van Rossuma9e20242007-03-08 00:43:48 +0000218
219class OtherFileTests(unittest.TestCase):
220
221 def testAbles(self):
222 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000223 f = _FileIO(TESTFN, "w")
Guido van Rossuma9e20242007-03-08 00:43:48 +0000224 self.assertEquals(f.readable(), False)
225 self.assertEquals(f.writable(), True)
226 self.assertEquals(f.seekable(), True)
227 f.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000228
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000229 f = _FileIO(TESTFN, "r")
Guido van Rossuma9e20242007-03-08 00:43:48 +0000230 self.assertEquals(f.readable(), True)
231 self.assertEquals(f.writable(), False)
232 self.assertEquals(f.seekable(), True)
233 f.close()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000234
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000235 f = _FileIO(TESTFN, "a+")
Guido van Rossuma9e20242007-03-08 00:43:48 +0000236 self.assertEquals(f.readable(), True)
237 self.assertEquals(f.writable(), True)
238 self.assertEquals(f.seekable(), True)
239 self.assertEquals(f.isatty(), False)
240 f.close()
Guido van Rossum682faf82007-04-12 14:56:58 +0000241
Thomas Hellerb0f48ab2007-07-12 11:29:02 +0000242 if sys.platform != "win32":
243 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000244 f = _FileIO("/dev/tty", "a")
Thomas Hellerb0f48ab2007-07-12 11:29:02 +0000245 except EnvironmentError:
246 # When run in a cron job there just aren't any
247 # ttys, so skip the test. This also handles other
248 # OS'es that don't support /dev/tty.
249 pass
250 else:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000251 f = _FileIO("/dev/tty", "a")
Thomas Hellerb0f48ab2007-07-12 11:29:02 +0000252 self.assertEquals(f.readable(), False)
253 self.assertEquals(f.writable(), True)
Hye-Shik Changcaf871a2007-08-13 13:21:33 +0000254 if sys.platform != "darwin" and \
Antoine Pitroud7b30462009-05-23 16:34:50 +0000255 'bsd' not in sys.platform and \
Benjamin Peterson94fe10f2008-07-17 23:27:26 +0000256 not sys.platform.startswith('sunos'):
Hye-Shik Changcaf871a2007-08-13 13:21:33 +0000257 # Somehow /dev/tty appears seekable on some BSDs
Thomas Hellerb0f48ab2007-07-12 11:29:02 +0000258 self.assertEquals(f.seekable(), False)
259 self.assertEquals(f.isatty(), True)
260 f.close()
Guido van Rossuma9e20242007-03-08 00:43:48 +0000261 finally:
262 os.unlink(TESTFN)
263
264 def testModeStrings(self):
265 # check invalid mode strings
Benjamin Peterson44309e62008-11-22 00:41:45 +0000266 for mode in ("", "aU", "wU+", "rw", "rt"):
Guido van Rossuma9e20242007-03-08 00:43:48 +0000267 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000268 f = _FileIO(TESTFN, mode)
Guido van Rossuma9e20242007-03-08 00:43:48 +0000269 except ValueError:
270 pass
271 else:
272 f.close()
273 self.fail('%r is an invalid file mode' % mode)
274
Guido van Rossuma9e20242007-03-08 00:43:48 +0000275 def testUnicodeOpen(self):
276 # verify repr works for unicode too
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000277 f = _FileIO(str(TESTFN), "w")
Guido van Rossuma9e20242007-03-08 00:43:48 +0000278 f.close()
279 os.unlink(TESTFN)
280
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000281 def testBytesOpen(self):
282 # Opening a bytes filename
283 try:
284 fn = TESTFN.encode("ascii")
285 except UnicodeEncodeError:
286 # Skip test
287 return
288 f = _FileIO(fn, "w")
289 try:
290 f.write(b"abc")
291 f.close()
292 with open(TESTFN, "rb") as f:
293 self.assertEquals(f.read(), b"abc")
294 finally:
295 os.unlink(TESTFN)
296
Benjamin Peterson806d4022009-01-19 15:11:51 +0000297 def testInvalidFd(self):
Antoine Pitrou7fb111b2009-03-04 11:14:01 +0000298 self.assertRaises(ValueError, _FileIO, -10)
299 self.assertRaises(OSError, _FileIO, make_bad_fd())
Benjamin Peterson806d4022009-01-19 15:11:51 +0000300
Guido van Rossuma9e20242007-03-08 00:43:48 +0000301 def testBadModeArgument(self):
302 # verify that we get a sensible error message for bad mode argument
303 bad_mode = "qwerty"
304 try:
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000305 f = _FileIO(TESTFN, bad_mode)
Guido van Rossuma9e20242007-03-08 00:43:48 +0000306 except ValueError as msg:
Guido van Rossum360e4b82007-05-14 22:51:27 +0000307 if msg.args[0] != 0:
Guido van Rossuma9e20242007-03-08 00:43:48 +0000308 s = str(msg)
309 if s.find(TESTFN) != -1 or s.find(bad_mode) == -1:
310 self.fail("bad error message for invalid mode: %s" % s)
Georg Brandl50da60c2008-01-06 21:38:54 +0000311 # if msg.args[0] == 0, we're probably on Windows where there may be
Guido van Rossuma9e20242007-03-08 00:43:48 +0000312 # no obvious way to discover why open() failed.
313 else:
314 f.close()
315 self.fail("no error for invalid mode: %s" % bad_mode)
316
317 def testTruncateOnWindows(self):
318 def bug801631():
319 # SF bug <http://www.python.org/sf/801631>
320 # "file.truncate fault on windows"
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000321 f = _FileIO(TESTFN, 'w')
Guido van Rossuma9e20242007-03-08 00:43:48 +0000322 f.write(bytes(range(11)))
323 f.close()
324
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000325 f = _FileIO(TESTFN,'r+')
Guido van Rossuma9e20242007-03-08 00:43:48 +0000326 data = f.read(5)
327 if data != bytes(range(5)):
328 self.fail("Read on file opened for update failed %r" % data)
329 if f.tell() != 5:
330 self.fail("File pos after read wrong %d" % f.tell())
331
332 f.truncate()
333 if f.tell() != 5:
334 self.fail("File pos after ftruncate wrong %d" % f.tell())
335
336 f.close()
337 size = os.path.getsize(TESTFN)
338 if size != 5:
339 self.fail("File size after ftruncate wrong %d" % size)
340
341 try:
342 bug801631()
343 finally:
344 os.unlink(TESTFN)
345
Walter Dörwald3a77c7a2007-06-06 16:31:14 +0000346 def testAppend(self):
347 try:
348 f = open(TESTFN, 'wb')
349 f.write(b'spam')
350 f.close()
351 f = open(TESTFN, 'ab')
352 f.write(b'eggs')
353 f.close()
354 f = open(TESTFN, 'rb')
355 d = f.read()
356 f.close()
357 self.assertEqual(d, b'spameggs')
358 finally:
359 try:
360 os.unlink(TESTFN)
361 except:
362 pass
363
Neal Norwitz6e0e0e62008-08-24 22:07:28 +0000364 def testInvalidInit(self):
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000365 self.assertRaises(TypeError, _FileIO, "1", 0, 0)
Neal Norwitz6e0e0e62008-08-24 22:07:28 +0000366
Benjamin Peterson65676e42008-11-05 21:42:45 +0000367 def testWarnings(self):
368 with check_warnings() as w:
369 self.assertEqual(w.warnings, [])
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000370 self.assertRaises(TypeError, _FileIO, [])
Benjamin Peterson65676e42008-11-05 21:42:45 +0000371 self.assertEqual(w.warnings, [])
Benjamin Peterson4fa88fa2009-03-04 00:14:51 +0000372 self.assertRaises(ValueError, _FileIO, "/some/invalid/name", "rt")
Benjamin Peterson65676e42008-11-05 21:42:45 +0000373 self.assertEqual(w.warnings, [])
374
Neal Norwitz6e0e0e62008-08-24 22:07:28 +0000375
Guido van Rossuma9e20242007-03-08 00:43:48 +0000376def test_main():
377 # Historically, these tests have been sloppy about removing TESTFN.
378 # So get rid of it no matter what.
379 try:
380 run_unittest(AutoFileTests, OtherFileTests)
381 finally:
382 if os.path.exists(TESTFN):
383 os.unlink(TESTFN)
384
385if __name__ == '__main__':
386 test_main()