blob: 73cb5b2412780a695befde5047cf61e7719d85f6 [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
Georg Brandl442b49e2006-06-08 14:50:53 +0000119
120class OtherFileTests(unittest.TestCase):
121
122 def testModeStrings(self):
123 # check invalid mode strings
124 for mode in ("", "aU", "wU+"):
125 try:
Tim Petersdbb82f62006-06-09 03:51:41 +0000126 f = open(TESTFN, mode)
Georg Brandl442b49e2006-06-08 14:50:53 +0000127 except ValueError:
128 pass
129 else:
130 f.close()
131 self.fail('%r is an invalid file mode' % mode)
132
133 def testStdin(self):
134 # This causes the interpreter to exit on OSF1 v5.1.
135 if sys.platform != 'osf1V5':
136 self.assertRaises(IOError, sys.stdin.seek, -1)
Thomas Woutersc45251a2006-02-12 11:53:32 +0000137 else:
Georg Brandl442b49e2006-06-08 14:50:53 +0000138 print >>sys.__stdout__, (
139 ' Skipping sys.stdin.seek(-1), it may crash the interpreter.'
140 ' Test manually.')
141 self.assertRaises(IOError, sys.stdin.truncate)
142
143 def testUnicodeOpen(self):
144 # verify repr works for unicode too
145 f = open(unicode(TESTFN), "w")
146 self.assert_(repr(f).startswith("<open file u'" + TESTFN))
Thomas Woutersc45251a2006-02-12 11:53:32 +0000147 f.close()
Tim Peters0556e9b2006-06-09 04:02:06 +0000148 os.unlink(TESTFN)
Thomas Woutersc45251a2006-02-12 11:53:32 +0000149
Georg Brandl442b49e2006-06-08 14:50:53 +0000150 def testBadModeArgument(self):
151 # verify that we get a sensible error message for bad mode argument
152 bad_mode = "qwerty"
Tim Peterscffcfed2006-02-14 17:41:18 +0000153 try:
Georg Brandl442b49e2006-06-08 14:50:53 +0000154 f = open(TESTFN, bad_mode)
155 except ValueError, msg:
156 if msg[0] != 0:
157 s = str(msg)
158 if s.find(TESTFN) != -1 or s.find(bad_mode) == -1:
159 self.fail("bad error message for invalid mode: %s" % s)
160 # if msg[0] == 0, we're probably on Windows where there may be
161 # no obvious way to discover why open() failed.
162 else:
163 f.close()
164 self.fail("no error for invalid mode: %s" % bad_mode)
165
166 def testSetBufferSize(self):
167 # make sure that explicitly setting the buffer size doesn't cause
168 # misbehaviour especially with repeated close() calls
169 for s in (-1, 0, 1, 512):
170 try:
171 f = open(TESTFN, 'w', s)
172 f.write(str(s))
173 f.close()
174 f.close()
175 f = open(TESTFN, 'r', s)
176 d = int(f.read())
177 f.close()
178 f.close()
179 except IOError, msg:
180 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
181 self.assertEquals(d, s)
182
183 def testTruncateOnWindows(self):
184 os.unlink(TESTFN)
185
186 def bug801631():
187 # SF bug <http://www.python.org/sf/801631>
188 # "file.truncate fault on windows"
Tim Petersdbb82f62006-06-09 03:51:41 +0000189 f = open(TESTFN, 'wb')
Georg Brandl442b49e2006-06-08 14:50:53 +0000190 f.write('12345678901') # 11 bytes
191 f.close()
192
Tim Petersdbb82f62006-06-09 03:51:41 +0000193 f = open(TESTFN,'rb+')
Georg Brandl442b49e2006-06-08 14:50:53 +0000194 data = f.read(5)
195 if data != '12345':
196 self.fail("Read on file opened for update failed %r" % data)
197 if f.tell() != 5:
198 self.fail("File pos after read wrong %d" % f.tell())
199
200 f.truncate()
201 if f.tell() != 5:
202 self.fail("File pos after ftruncate wrong %d" % f.tell())
203
204 f.close()
205 size = os.path.getsize(TESTFN)
206 if size != 5:
207 self.fail("File size after ftruncate wrong %d" % size)
208
209 try:
210 bug801631()
211 finally:
212 os.unlink(TESTFN)
213
214 def testIteration(self):
Tim Petersdbb82f62006-06-09 03:51:41 +0000215 # Test the complex interaction when mixing file-iteration and the
216 # various read* methods. Ostensibly, the mixture could just be tested
217 # to work when it should work according to the Python language,
218 # instead of fail when it should fail according to the current CPython
219 # implementation. People don't always program Python the way they
220 # should, though, and the implemenation might change in subtle ways,
221 # so we explicitly test for errors, too; the test will just have to
222 # be updated when the implementation changes.
Georg Brandl442b49e2006-06-08 14:50:53 +0000223 dataoffset = 16384
224 filler = "ham\n"
225 assert not dataoffset % len(filler), \
226 "dataoffset must be multiple of len(filler)"
227 nchunks = dataoffset // len(filler)
228 testlines = [
229 "spam, spam and eggs\n",
230 "eggs, spam, ham and spam\n",
231 "saussages, spam, spam and eggs\n",
232 "spam, ham, spam and eggs\n",
233 "spam, spam, spam, spam, spam, ham, spam\n",
234 "wonderful spaaaaaam.\n"
235 ]
236 methods = [("readline", ()), ("read", ()), ("readlines", ()),
237 ("readinto", (array("c", " "*100),))]
238
239 try:
240 # Prepare the testfile
241 bag = open(TESTFN, "w")
242 bag.write(filler * nchunks)
243 bag.writelines(testlines)
244 bag.close()
245 # Test for appropriate errors mixing read* and iteration
246 for methodname, args in methods:
247 f = open(TESTFN)
248 if f.next() != filler:
249 self.fail, "Broken testfile"
250 meth = getattr(f, methodname)
251 try:
252 meth(*args)
253 except ValueError:
254 pass
255 else:
256 self.fail("%s%r after next() didn't raise ValueError" %
257 (methodname, args))
258 f.close()
259
Tim Petersdbb82f62006-06-09 03:51:41 +0000260 # 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).
Georg Brandl442b49e2006-06-08 14:50:53 +0000267 f = open(TESTFN)
268 for i in range(nchunks):
269 f.next()
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("c", "\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.tostring()
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 # Reading after iteration hit EOF shouldn't hurt either
309 f = open(TESTFN)
310 try:
311 for line in f:
312 pass
313 try:
314 f.readline()
315 f.readinto(buf)
316 f.read()
317 f.readlines()
318 except ValueError:
319 self.fail("read* failed after next() consumed file")
320 finally:
321 f.close()
322 finally:
323 os.unlink(TESTFN)
324
325
326def test_main():
Neal Norwitzc9778a82006-06-09 05:54:18 +0000327 # Historically, these tests have been sloppy about removing TESTFN.
328 # So get rid of it no matter what.
Tim Peters0556e9b2006-06-09 04:02:06 +0000329 try:
330 run_unittest(AutoFileTests, OtherFileTests)
331 finally:
332 if os.path.exists(TESTFN):
333 os.unlink(TESTFN)
Georg Brandl442b49e2006-06-08 14:50:53 +0000334
335if __name__ == '__main__':
336 test_main()