blob: f678df6f370d9069943f0d66efe808e5fdd09890 [file] [log] [blame]
Martin v. Löwisf90ae202002-06-11 06:22:31 +00001import sys
Fred Drake2ec80fa2000-10-23 16:59:35 +00002import os
Georg Brandl442b49e2006-06-08 14:50:53 +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
Georg Brandl442b49e2006-06-08 14:50:53 +00007from test.test_support import TESTFN, findfile, run_unittest
Marc-André Lemburgfa44d792000-08-25 22:37:31 +00008from UserList import UserList
9
Georg Brandl442b49e2006-06-08 14:50:53 +000010class AutoFileTests(unittest.TestCase):
11 # file tests for which a test file is automatically set up
Raymond Hettingercb87bc82004-05-31 00:35:52 +000012
Georg Brandl442b49e2006-06-08 14:50:53 +000013 def setUp(self):
Tim Petersdbb82f62006-06-09 03:51:41 +000014 self.f = open(TESTFN, 'wb')
Tim Peters015dd822003-05-04 04:16:52 +000015
Georg Brandl442b49e2006-06-08 14:50:53 +000016 def tearDown(self):
Tim Petersdbb82f62006-06-09 03:51:41 +000017 if self.f:
18 self.f.close()
19 os.remove(TESTFN)
Georg Brandl442b49e2006-06-08 14:50:53 +000020
21 def testWeakRefs(self):
22 # verify weak references
23 p = proxy(self.f)
24 p.write('teststring')
25 self.assertEquals(self.f.tell(), p.tell())
26 self.f.close()
27 self.f = None
28 self.assertRaises(ReferenceError, getattr, p, 'tell')
29
30 def testAttributes(self):
31 # verify expected attributes exist
32 f = self.f
33 softspace = f.softspace
34 f.name # merely shouldn't blow up
35 f.mode # ditto
36 f.closed # ditto
37
38 # verify softspace is writable
39 f.softspace = softspace # merely shouldn't blow up
40
41 # verify the others aren't
42 for attr in 'name', 'mode', 'closed':
43 self.assertRaises((AttributeError, TypeError), setattr, f, attr, 'oops')
44
45 def testReadinto(self):
46 # verify readinto
47 self.f.write('12')
48 self.f.close()
49 a = array('c', 'x'*10)
50 self.f = open(TESTFN, 'rb')
51 n = self.f.readinto(a)
52 self.assertEquals('12', a.tostring()[:n])
53
54 def testWritelinesUserList(self):
55 # verify writelines with instance sequence
56 l = UserList(['1', '2'])
57 self.f.writelines(l)
58 self.f.close()
59 self.f = open(TESTFN, 'rb')
60 buf = self.f.read()
61 self.assertEquals(buf, '12')
62
63 def testWritelinesIntegers(self):
64 # verify writelines with integers
65 self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
66
67 def testWritelinesIntegersUserList(self):
68 # verify writelines with integers in UserList
69 l = UserList([1,2,3])
70 self.assertRaises(TypeError, self.f.writelines, l)
71
72 def testWritelinesNonString(self):
73 # verify writelines with non-string object
Tim Petersdbb82f62006-06-09 03:51:41 +000074 class NonString:
75 pass
Georg Brandl442b49e2006-06-08 14:50:53 +000076
Tim Petersdbb82f62006-06-09 03:51:41 +000077 self.assertRaises(TypeError, self.f.writelines,
78 [NonString(), NonString()])
Georg Brandl442b49e2006-06-08 14:50:53 +000079
80 def testRepr(self):
81 # verify repr works
82 self.assert_(repr(self.f).startswith("<open file '" + TESTFN))
83
84 def testErrors(self):
85 f = self.f
86 self.assertEquals(f.name, TESTFN)
87 self.assert_(not f.isatty())
88 self.assert_(not f.closed)
Tim Peters520d8dd2006-06-09 02:11:02 +000089
Georg Brandl442b49e2006-06-08 14:50:53 +000090 self.assertRaises(TypeError, f.readinto, "")
91 f.close()
92 self.assert_(f.closed)
93
94 def testMethods(self):
95 methods = ['fileno', 'flush', 'isatty', 'next', 'read', 'readinto',
Tim Petersdbb82f62006-06-09 03:51:41 +000096 'readline', 'readlines', 'seek', 'tell', 'truncate',
97 'write', 'xreadlines', '__iter__']
Georg Brandl442b49e2006-06-08 14:50:53 +000098 if sys.platform.startswith('atheos'):
99 methods.remove('truncate')
100
Georg Brandle7ec81f2006-06-09 18:29:52 +0000101 # __exit__ should close the file
102 self.f.__exit__(None, None, None)
103 self.assert_(self.f.closed)
Georg Brandl442b49e2006-06-08 14:50:53 +0000104
105 for methodname in methods:
106 method = getattr(self.f, methodname)
107 # should raise on closed file
108 self.assertRaises(ValueError, method)
109 self.assertRaises(ValueError, self.f.writelines, [])
110
Georg Brandle7ec81f2006-06-09 18:29:52 +0000111 # file is closed, __exit__ shouldn't do anything
112 self.assertEquals(self.f.__exit__(None, None, None), None)
113 # it must also return None if an exception was given
114 try:
115 1/0
116 except:
117 self.assertEquals(self.f.__exit__(*sys.exc_info()), None)
118
Martin v. Löwisedf14312008-12-23 13:07:51 +0000119 def testReadWhenWriting(self):
120 self.assertRaises(IOError, self.f.read)
Georg Brandl442b49e2006-06-08 14:50:53 +0000121
122class OtherFileTests(unittest.TestCase):
123
124 def testModeStrings(self):
125 # check invalid mode strings
126 for mode in ("", "aU", "wU+"):
127 try:
Tim Petersdbb82f62006-06-09 03:51:41 +0000128 f = open(TESTFN, mode)
Georg Brandl442b49e2006-06-08 14:50:53 +0000129 except ValueError:
130 pass
131 else:
132 f.close()
133 self.fail('%r is an invalid file mode' % mode)
134
135 def testStdin(self):
136 # This causes the interpreter to exit on OSF1 v5.1.
137 if sys.platform != 'osf1V5':
138 self.assertRaises(IOError, sys.stdin.seek, -1)
Thomas Woutersc45251a2006-02-12 11:53:32 +0000139 else:
Georg Brandl442b49e2006-06-08 14:50:53 +0000140 print >>sys.__stdout__, (
141 ' Skipping sys.stdin.seek(-1), it may crash the interpreter.'
142 ' Test manually.')
143 self.assertRaises(IOError, sys.stdin.truncate)
144
145 def testUnicodeOpen(self):
146 # verify repr works for unicode too
147 f = open(unicode(TESTFN), "w")
148 self.assert_(repr(f).startswith("<open file u'" + TESTFN))
Thomas Woutersc45251a2006-02-12 11:53:32 +0000149 f.close()
Tim Peters0556e9b2006-06-09 04:02:06 +0000150 os.unlink(TESTFN)
Thomas Woutersc45251a2006-02-12 11:53:32 +0000151
Georg Brandl442b49e2006-06-08 14:50:53 +0000152 def testBadModeArgument(self):
153 # verify that we get a sensible error message for bad mode argument
154 bad_mode = "qwerty"
Tim Peterscffcfed2006-02-14 17:41:18 +0000155 try:
Georg Brandl442b49e2006-06-08 14:50:53 +0000156 f = open(TESTFN, bad_mode)
157 except ValueError, msg:
158 if msg[0] != 0:
159 s = str(msg)
160 if s.find(TESTFN) != -1 or s.find(bad_mode) == -1:
161 self.fail("bad error message for invalid mode: %s" % s)
162 # if msg[0] == 0, we're probably on Windows where there may be
163 # no obvious way to discover why open() failed.
164 else:
165 f.close()
166 self.fail("no error for invalid mode: %s" % bad_mode)
167
168 def testSetBufferSize(self):
169 # make sure that explicitly setting the buffer size doesn't cause
170 # misbehaviour especially with repeated close() calls
171 for s in (-1, 0, 1, 512):
172 try:
173 f = open(TESTFN, 'w', s)
174 f.write(str(s))
175 f.close()
176 f.close()
177 f = open(TESTFN, 'r', s)
178 d = int(f.read())
179 f.close()
180 f.close()
181 except IOError, msg:
182 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
183 self.assertEquals(d, s)
184
185 def testTruncateOnWindows(self):
186 os.unlink(TESTFN)
187
188 def bug801631():
189 # SF bug <http://www.python.org/sf/801631>
190 # "file.truncate fault on windows"
Tim Petersdbb82f62006-06-09 03:51:41 +0000191 f = open(TESTFN, 'wb')
Georg Brandl442b49e2006-06-08 14:50:53 +0000192 f.write('12345678901') # 11 bytes
193 f.close()
194
Tim Petersdbb82f62006-06-09 03:51:41 +0000195 f = open(TESTFN,'rb+')
Georg Brandl442b49e2006-06-08 14:50:53 +0000196 data = f.read(5)
197 if data != '12345':
198 self.fail("Read on file opened for update failed %r" % data)
199 if f.tell() != 5:
200 self.fail("File pos after read wrong %d" % f.tell())
201
202 f.truncate()
203 if f.tell() != 5:
204 self.fail("File pos after ftruncate wrong %d" % f.tell())
205
206 f.close()
207 size = os.path.getsize(TESTFN)
208 if size != 5:
209 self.fail("File size after ftruncate wrong %d" % size)
210
211 try:
212 bug801631()
213 finally:
214 os.unlink(TESTFN)
215
216 def testIteration(self):
Tim Petersdbb82f62006-06-09 03:51:41 +0000217 # Test the complex interaction when mixing file-iteration and the
218 # various read* methods. Ostensibly, the mixture could just be tested
219 # to work when it should work according to the Python language,
220 # instead of fail when it should fail according to the current CPython
221 # implementation. People don't always program Python the way they
222 # should, though, and the implemenation might change in subtle ways,
223 # so we explicitly test for errors, too; the test will just have to
224 # be updated when the implementation changes.
Georg Brandl442b49e2006-06-08 14:50:53 +0000225 dataoffset = 16384
226 filler = "ham\n"
227 assert not dataoffset % len(filler), \
228 "dataoffset must be multiple of len(filler)"
229 nchunks = dataoffset // len(filler)
230 testlines = [
231 "spam, spam and eggs\n",
232 "eggs, spam, ham and spam\n",
233 "saussages, spam, spam and eggs\n",
234 "spam, ham, spam and eggs\n",
235 "spam, spam, spam, spam, spam, ham, spam\n",
236 "wonderful spaaaaaam.\n"
237 ]
238 methods = [("readline", ()), ("read", ()), ("readlines", ()),
239 ("readinto", (array("c", " "*100),))]
240
241 try:
242 # Prepare the testfile
243 bag = open(TESTFN, "w")
244 bag.write(filler * nchunks)
245 bag.writelines(testlines)
246 bag.close()
247 # Test for appropriate errors mixing read* and iteration
248 for methodname, args in methods:
249 f = open(TESTFN)
250 if f.next() != filler:
251 self.fail, "Broken testfile"
252 meth = getattr(f, methodname)
253 try:
254 meth(*args)
255 except ValueError:
256 pass
257 else:
258 self.fail("%s%r after next() didn't raise ValueError" %
259 (methodname, args))
260 f.close()
261
Tim Petersdbb82f62006-06-09 03:51:41 +0000262 # Test to see if harmless (by accident) mixing of read* and
263 # iteration still works. This depends on the size of the internal
264 # iteration buffer (currently 8192,) but we can test it in a
265 # flexible manner. Each line in the bag o' ham is 4 bytes
266 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
267 # exactly on the buffer boundary for any power-of-2 buffersize
268 # between 4 and 16384 (inclusive).
Georg Brandl442b49e2006-06-08 14:50:53 +0000269 f = open(TESTFN)
270 for i in range(nchunks):
271 f.next()
272 testline = testlines.pop(0)
273 try:
274 line = f.readline()
275 except ValueError:
276 self.fail("readline() after next() with supposedly empty "
277 "iteration-buffer failed anyway")
278 if line != testline:
279 self.fail("readline() after next() with empty buffer "
280 "failed. Got %r, expected %r" % (line, testline))
281 testline = testlines.pop(0)
282 buf = array("c", "\x00" * len(testline))
283 try:
284 f.readinto(buf)
285 except ValueError:
286 self.fail("readinto() after next() with supposedly empty "
287 "iteration-buffer failed anyway")
288 line = buf.tostring()
289 if line != testline:
290 self.fail("readinto() after next() with empty buffer "
291 "failed. Got %r, expected %r" % (line, testline))
292
293 testline = testlines.pop(0)
294 try:
295 line = f.read(len(testline))
296 except ValueError:
297 self.fail("read() after next() with supposedly empty "
298 "iteration-buffer failed anyway")
299 if line != testline:
300 self.fail("read() after next() with empty buffer "
301 "failed. Got %r, expected %r" % (line, testline))
302 try:
303 lines = f.readlines()
304 except ValueError:
305 self.fail("readlines() after next() with supposedly empty "
306 "iteration-buffer failed anyway")
307 if lines != testlines:
308 self.fail("readlines() after next() with empty buffer "
309 "failed. Got %r, expected %r" % (line, testline))
310 # Reading after iteration hit EOF shouldn't hurt either
311 f = open(TESTFN)
312 try:
313 for line in f:
314 pass
315 try:
316 f.readline()
317 f.readinto(buf)
318 f.read()
319 f.readlines()
320 except ValueError:
321 self.fail("read* failed after next() consumed file")
322 finally:
323 f.close()
324 finally:
325 os.unlink(TESTFN)
326
327
Amaury Forgeot d'Arcceda6a62008-07-01 20:52:56 +0000328class StdoutTests(unittest.TestCase):
329
330 def test_move_stdout_on_write(self):
331 # Issue 3242: sys.stdout can be replaced (and freed) during a
332 # print statement; prevent a segfault in this case
333 save_stdout = sys.stdout
334
335 class File:
336 def write(self, data):
337 if '\n' in data:
338 sys.stdout = save_stdout
339
340 try:
341 sys.stdout = File()
342 print "some text"
343 finally:
344 sys.stdout = save_stdout
345
Jeffrey Yasskin6f5d3f32008-12-10 17:23:20 +0000346 def test_del_stdout_before_print(self):
347 # Issue 4597: 'print' with no argument wasn't reporting when
348 # sys.stdout was deleted.
349 save_stdout = sys.stdout
350 del sys.stdout
351 try:
352 print
353 except RuntimeError, e:
354 self.assertEquals(str(e), "lost sys.stdout")
355 else:
356 self.fail("Expected RuntimeError")
357 finally:
358 sys.stdout = save_stdout
359
Martin v. Löwis084486b2008-12-13 15:36:49 +0000360 def testReadAfterEOF(self):
361 # Regression test for SF bug #1523853.
362 # Verify read works after hitting EOF
363
364 # Prepare the testfile
365 teststring = "spam"
366 bag = open(TESTFN, "w")
367 bag.write(teststring)
368 bag.close()
369
370 # And buf for readinto
371 buf = array("c", " "*len(teststring))
372
373 # Test for appropriate errors mixing read* and iteration
374 methods = [("readline", ()), ("read",()), ("readlines", ()),
375 ("readinto", (buf,))]
376
377 for attr in 'r', 'rU':
378 for methodname, args in methods:
379 f = open(TESTFN, "rU")
380 f.seek(0, 2)
381 meth = getattr(f, methodname)
382 meth(*args) # hits EOF
383 try:
384 # Writing the same file with another file descriptor
385 append = open(TESTFN, "a+")
386 append.write(teststring)
387 append.flush()
388 append.close()
389 try:
390 meth = getattr(f, methodname)
391 if methodname == 'readlines':
392 self.failUnlessEqual(meth(*args), [teststring])
393 elif methodname == 'readinto':
394 meth(*args)
395 self.failUnlessEqual(buf.tostring(), teststring)
396 else:
397 self.failUnlessEqual(meth(*args), teststring)
398 except ValueError:
399 self.fail("read* failed after hitting EOF")
400 finally:
401 f.close()
Amaury Forgeot d'Arcceda6a62008-07-01 20:52:56 +0000402
Georg Brandl442b49e2006-06-08 14:50:53 +0000403def test_main():
Neal Norwitzc9778a82006-06-09 05:54:18 +0000404 # Historically, these tests have been sloppy about removing TESTFN.
405 # So get rid of it no matter what.
Tim Peters0556e9b2006-06-09 04:02:06 +0000406 try:
Amaury Forgeot d'Arcceda6a62008-07-01 20:52:56 +0000407 run_unittest(AutoFileTests, OtherFileTests, StdoutTests)
Tim Peters0556e9b2006-06-09 04:02:06 +0000408 finally:
409 if os.path.exists(TESTFN):
410 os.unlink(TESTFN)
Georg Brandl442b49e2006-06-08 14:50:53 +0000411
412if __name__ == '__main__':
413 test_main()