blob: 52c4a02fd6a891a9a00d32462d617c52996da2cb [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
Thomas Wouters73e5a5b2006-06-08 15:35:45 +00007from test.test_support import TESTFN, findfile, run_unittest
Marc-André Lemburgfa44d792000-08-25 22:37:31 +00008from UserList import UserList
9
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000010class AutoFileTests(unittest.TestCase):
11 # file tests for which a test file is automatically set up
Raymond Hettingercb87bc82004-05-31 00:35:52 +000012
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000013 def setUp(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000014 self.f = open(TESTFN, 'wb')
Tim Peters015dd822003-05-04 04:16:52 +000015
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000016 def tearDown(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000017 if self.f:
18 self.f.close()
19 os.remove(TESTFN)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +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 testReadinto_text(self):
55 # verify readinto refuses text files
56 a = array('c', 'x'*10)
57 self.f.close()
58 self.f = open(TESTFN, 'r')
59 self.assertRaises(TypeError, self.f.readinto, a)
60
61 def testWritelinesUserList(self):
62 # verify writelines with instance sequence
63 l = UserList(['1', '2'])
64 self.f.writelines(l)
65 self.f.close()
66 self.f = open(TESTFN, 'rb')
67 buf = self.f.read()
68 self.assertEquals(buf, '12')
69
70 def testWritelinesIntegers(self):
71 # verify writelines with integers
72 self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
73
74 def testWritelinesIntegersUserList(self):
75 # verify writelines with integers in UserList
76 l = UserList([1,2,3])
77 self.assertRaises(TypeError, self.f.writelines, l)
78
79 def testWritelinesNonString(self):
80 # verify writelines with non-string object
Thomas Wouters0e3f5912006-08-11 14:57:12 +000081 class NonString:
82 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000083
Thomas Wouters0e3f5912006-08-11 14:57:12 +000084 self.assertRaises(TypeError, self.f.writelines,
85 [NonString(), NonString()])
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000086
87 def testRepr(self):
88 # verify repr works
89 self.assert_(repr(self.f).startswith("<open file '" + TESTFN))
90
91 def testErrors(self):
92 f = self.f
93 self.assertEquals(f.name, TESTFN)
94 self.assert_(not f.isatty())
95 self.assert_(not f.closed)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000096
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000097 self.assertRaises(TypeError, f.readinto, "")
98 f.close()
99 self.assert_(f.closed)
100
101 def testMethods(self):
102 methods = ['fileno', 'flush', 'isatty', 'next', 'read', 'readinto',
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000103 'readline', 'readlines', 'seek', 'tell', 'truncate',
104 'write', '__iter__']
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000105 if sys.platform.startswith('atheos'):
106 methods.remove('truncate')
107
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000108 # __exit__ should close the file
109 self.f.__exit__(None, None, None)
110 self.assert_(self.f.closed)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000111
112 for methodname in methods:
113 method = getattr(self.f, methodname)
114 # should raise on closed file
115 self.assertRaises(ValueError, method)
116 self.assertRaises(ValueError, self.f.writelines, [])
117
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000118 # file is closed, __exit__ shouldn't do anything
119 self.assertEquals(self.f.__exit__(None, None, None), None)
120 # it must also return None if an exception was given
121 try:
122 1/0
123 except:
124 self.assertEquals(self.f.__exit__(*sys.exc_info()), None)
125
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000126
127class OtherFileTests(unittest.TestCase):
128
129 def testModeStrings(self):
130 # check invalid mode strings
131 for mode in ("", "aU", "wU+"):
132 try:
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000133 f = open(TESTFN, mode)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000134 except ValueError:
135 pass
136 else:
137 f.close()
138 self.fail('%r is an invalid file mode' % mode)
139
140 def testStdin(self):
141 # This causes the interpreter to exit on OSF1 v5.1.
142 if sys.platform != 'osf1V5':
143 self.assertRaises(IOError, sys.stdin.seek, -1)
Thomas Woutersc45251a2006-02-12 11:53:32 +0000144 else:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000145 print >>sys.__stdout__, (
146 ' Skipping sys.stdin.seek(-1), it may crash the interpreter.'
147 ' Test manually.')
148 self.assertRaises(IOError, sys.stdin.truncate)
149
150 def testUnicodeOpen(self):
151 # verify repr works for unicode too
152 f = open(unicode(TESTFN), "w")
153 self.assert_(repr(f).startswith("<open file u'" + TESTFN))
Thomas Woutersc45251a2006-02-12 11:53:32 +0000154 f.close()
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000155 os.unlink(TESTFN)
Thomas Woutersc45251a2006-02-12 11:53:32 +0000156
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:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000161 f = open(TESTFN, bad_mode)
Guido van Rossumb940e112007-01-10 16:19:56 +0000162 except ValueError as msg:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000163 if msg[0] != 0:
164 s = str(msg)
165 if s.find(TESTFN) != -1 or s.find(bad_mode) == -1:
166 self.fail("bad error message for invalid mode: %s" % s)
167 # if msg[0] == 0, we're probably on Windows where there may be
168 # 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
173 def testSetBufferSize(self):
174 # make sure that explicitly setting the buffer size doesn't cause
175 # misbehaviour especially with repeated close() calls
176 for s in (-1, 0, 1, 512):
177 try:
178 f = open(TESTFN, 'w', s)
179 f.write(str(s))
180 f.close()
181 f.close()
182 f = open(TESTFN, 'r', s)
183 d = int(f.read())
184 f.close()
185 f.close()
Guido van Rossumb940e112007-01-10 16:19:56 +0000186 except IOError as msg:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000187 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
188 self.assertEquals(d, s)
189
190 def testTruncateOnWindows(self):
191 os.unlink(TESTFN)
192
193 def bug801631():
194 # SF bug <http://www.python.org/sf/801631>
195 # "file.truncate fault on windows"
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000196 f = open(TESTFN, 'wb')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000197 f.write('12345678901') # 11 bytes
198 f.close()
199
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000200 f = open(TESTFN,'rb+')
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000201 data = f.read(5)
202 if data != '12345':
203 self.fail("Read on file opened for update failed %r" % data)
204 if f.tell() != 5:
205 self.fail("File pos after read wrong %d" % f.tell())
206
207 f.truncate()
208 if f.tell() != 5:
209 self.fail("File pos after ftruncate wrong %d" % f.tell())
210
211 f.close()
212 size = os.path.getsize(TESTFN)
213 if size != 5:
214 self.fail("File size after ftruncate wrong %d" % size)
215
216 try:
217 bug801631()
218 finally:
219 os.unlink(TESTFN)
220
221 def testIteration(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000222 # Test the complex interaction when mixing file-iteration and the
223 # various read* methods. Ostensibly, the mixture could just be tested
224 # to work when it should work according to the Python language,
225 # instead of fail when it should fail according to the current CPython
226 # implementation. People don't always program Python the way they
227 # should, though, and the implemenation might change in subtle ways,
228 # so we explicitly test for errors, too; the test will just have to
229 # be updated when the implementation changes.
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000230 dataoffset = 16384
231 filler = "ham\n"
232 assert not dataoffset % len(filler), \
233 "dataoffset must be multiple of len(filler)"
234 nchunks = dataoffset // len(filler)
235 testlines = [
236 "spam, spam and eggs\n",
237 "eggs, spam, ham and spam\n",
238 "saussages, spam, spam and eggs\n",
239 "spam, ham, spam and eggs\n",
240 "spam, spam, spam, spam, spam, ham, spam\n",
241 "wonderful spaaaaaam.\n"
242 ]
243 methods = [("readline", ()), ("read", ()), ("readlines", ()),
244 ("readinto", (array("c", " "*100),))]
245
246 try:
247 # Prepare the testfile
248 bag = 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:
254 f = open(TESTFN, 'rb')
255 if f.next() != filler:
256 self.fail, "Broken testfile"
257 meth = getattr(f, methodname)
258 try:
259 meth(*args)
260 except ValueError:
261 pass
262 else:
263 self.fail("%s%r after next() didn't raise ValueError" %
264 (methodname, args))
265 f.close()
266
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000267 # Test to see if harmless (by accident) mixing of read* and
268 # iteration still works. This depends on the size of the internal
269 # iteration buffer (currently 8192,) but we can test it in a
270 # flexible manner. Each line in the bag o' ham is 4 bytes
271 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
272 # exactly on the buffer boundary for any power-of-2 buffersize
273 # between 4 and 16384 (inclusive).
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000274 f = open(TESTFN, 'rb')
275 for i in range(nchunks):
276 f.next()
277 testline = testlines.pop(0)
278 try:
279 line = f.readline()
280 except ValueError:
281 self.fail("readline() after next() with supposedly empty "
282 "iteration-buffer failed anyway")
283 if line != testline:
284 self.fail("readline() after next() with empty buffer "
285 "failed. Got %r, expected %r" % (line, testline))
286 testline = testlines.pop(0)
287 buf = array("c", "\x00" * len(testline))
288 try:
289 f.readinto(buf)
290 except ValueError:
291 self.fail("readinto() after next() with supposedly empty "
292 "iteration-buffer failed anyway")
293 line = buf.tostring()
294 if line != testline:
295 self.fail("readinto() after next() with empty buffer "
296 "failed. Got %r, expected %r" % (line, testline))
297
298 testline = testlines.pop(0)
299 try:
300 line = f.read(len(testline))
301 except ValueError:
302 self.fail("read() after next() with supposedly empty "
303 "iteration-buffer failed anyway")
304 if line != testline:
305 self.fail("read() after next() with empty buffer "
306 "failed. Got %r, expected %r" % (line, testline))
307 try:
308 lines = f.readlines()
309 except ValueError:
310 self.fail("readlines() after next() with supposedly empty "
311 "iteration-buffer failed anyway")
312 if lines != testlines:
313 self.fail("readlines() after next() with empty buffer "
314 "failed. Got %r, expected %r" % (line, testline))
315 # Reading after iteration hit EOF shouldn't hurt either
316 f = open(TESTFN, 'rb')
317 try:
318 for line in f:
319 pass
320 try:
321 f.readline()
322 f.readinto(buf)
323 f.read()
324 f.readlines()
325 except ValueError:
326 self.fail("read* failed after next() consumed file")
327 finally:
328 f.close()
329 finally:
330 os.unlink(TESTFN)
331
332
333def test_main():
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000334 # Historically, these tests have been sloppy about removing TESTFN.
335 # So get rid of it no matter what.
336 try:
337 run_unittest(AutoFileTests, OtherFileTests)
338 finally:
339 if os.path.exists(TESTFN):
340 os.unlink(TESTFN)
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000341
342if __name__ == '__main__':
343 test_main()