blob: e19526a8791b73c8a07cfee00c14c54dd798c502 [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
101 self.f.close()
102
103 for methodname in methods:
104 method = getattr(self.f, methodname)
105 # should raise on closed file
106 self.assertRaises(ValueError, method)
107 self.assertRaises(ValueError, self.f.writelines, [])
108
109
110class OtherFileTests(unittest.TestCase):
111
112 def testModeStrings(self):
113 # check invalid mode strings
114 for mode in ("", "aU", "wU+"):
115 try:
Tim Petersdbb82f62006-06-09 03:51:41 +0000116 f = open(TESTFN, mode)
Georg Brandl442b49e2006-06-08 14:50:53 +0000117 except ValueError:
118 pass
119 else:
120 f.close()
121 self.fail('%r is an invalid file mode' % mode)
122
123 def testStdin(self):
124 # This causes the interpreter to exit on OSF1 v5.1.
125 if sys.platform != 'osf1V5':
126 self.assertRaises(IOError, sys.stdin.seek, -1)
Thomas Woutersc45251a2006-02-12 11:53:32 +0000127 else:
Georg Brandl442b49e2006-06-08 14:50:53 +0000128 print >>sys.__stdout__, (
129 ' Skipping sys.stdin.seek(-1), it may crash the interpreter.'
130 ' Test manually.')
131 self.assertRaises(IOError, sys.stdin.truncate)
132
133 def testUnicodeOpen(self):
134 # verify repr works for unicode too
135 f = open(unicode(TESTFN), "w")
136 self.assert_(repr(f).startswith("<open file u'" + TESTFN))
Thomas Woutersc45251a2006-02-12 11:53:32 +0000137 f.close()
138
Georg Brandl442b49e2006-06-08 14:50:53 +0000139 def testBadModeArgument(self):
140 # verify that we get a sensible error message for bad mode argument
141 bad_mode = "qwerty"
Tim Peterscffcfed2006-02-14 17:41:18 +0000142 try:
Georg Brandl442b49e2006-06-08 14:50:53 +0000143 f = open(TESTFN, bad_mode)
144 except ValueError, msg:
145 if msg[0] != 0:
146 s = str(msg)
147 if s.find(TESTFN) != -1 or s.find(bad_mode) == -1:
148 self.fail("bad error message for invalid mode: %s" % s)
149 # if msg[0] == 0, we're probably on Windows where there may be
150 # no obvious way to discover why open() failed.
151 else:
152 f.close()
153 self.fail("no error for invalid mode: %s" % bad_mode)
154
155 def testSetBufferSize(self):
156 # make sure that explicitly setting the buffer size doesn't cause
157 # misbehaviour especially with repeated close() calls
158 for s in (-1, 0, 1, 512):
159 try:
160 f = open(TESTFN, 'w', s)
161 f.write(str(s))
162 f.close()
163 f.close()
164 f = open(TESTFN, 'r', s)
165 d = int(f.read())
166 f.close()
167 f.close()
168 except IOError, msg:
169 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
170 self.assertEquals(d, s)
171
172 def testTruncateOnWindows(self):
173 os.unlink(TESTFN)
174
175 def bug801631():
176 # SF bug <http://www.python.org/sf/801631>
177 # "file.truncate fault on windows"
Tim Petersdbb82f62006-06-09 03:51:41 +0000178 f = open(TESTFN, 'wb')
Georg Brandl442b49e2006-06-08 14:50:53 +0000179 f.write('12345678901') # 11 bytes
180 f.close()
181
Tim Petersdbb82f62006-06-09 03:51:41 +0000182 f = open(TESTFN,'rb+')
Georg Brandl442b49e2006-06-08 14:50:53 +0000183 data = f.read(5)
184 if data != '12345':
185 self.fail("Read on file opened for update failed %r" % data)
186 if f.tell() != 5:
187 self.fail("File pos after read wrong %d" % f.tell())
188
189 f.truncate()
190 if f.tell() != 5:
191 self.fail("File pos after ftruncate wrong %d" % f.tell())
192
193 f.close()
194 size = os.path.getsize(TESTFN)
195 if size != 5:
196 self.fail("File size after ftruncate wrong %d" % size)
197
198 try:
199 bug801631()
200 finally:
201 os.unlink(TESTFN)
202
203 def testIteration(self):
Tim Petersdbb82f62006-06-09 03:51:41 +0000204 # Test the complex interaction when mixing file-iteration and the
205 # various read* methods. Ostensibly, the mixture could just be tested
206 # to work when it should work according to the Python language,
207 # instead of fail when it should fail according to the current CPython
208 # implementation. People don't always program Python the way they
209 # should, though, and the implemenation might change in subtle ways,
210 # so we explicitly test for errors, too; the test will just have to
211 # be updated when the implementation changes.
Georg Brandl442b49e2006-06-08 14:50:53 +0000212 dataoffset = 16384
213 filler = "ham\n"
214 assert not dataoffset % len(filler), \
215 "dataoffset must be multiple of len(filler)"
216 nchunks = dataoffset // len(filler)
217 testlines = [
218 "spam, spam and eggs\n",
219 "eggs, spam, ham and spam\n",
220 "saussages, spam, spam and eggs\n",
221 "spam, ham, spam and eggs\n",
222 "spam, spam, spam, spam, spam, ham, spam\n",
223 "wonderful spaaaaaam.\n"
224 ]
225 methods = [("readline", ()), ("read", ()), ("readlines", ()),
226 ("readinto", (array("c", " "*100),))]
227
228 try:
229 # Prepare the testfile
230 bag = open(TESTFN, "w")
231 bag.write(filler * nchunks)
232 bag.writelines(testlines)
233 bag.close()
234 # Test for appropriate errors mixing read* and iteration
235 for methodname, args in methods:
236 f = open(TESTFN)
237 if f.next() != filler:
238 self.fail, "Broken testfile"
239 meth = getattr(f, methodname)
240 try:
241 meth(*args)
242 except ValueError:
243 pass
244 else:
245 self.fail("%s%r after next() didn't raise ValueError" %
246 (methodname, args))
247 f.close()
248
Tim Petersdbb82f62006-06-09 03:51:41 +0000249 # 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).
Georg Brandl442b49e2006-06-08 14:50:53 +0000256 f = open(TESTFN)
257 for i in range(nchunks):
258 f.next()
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("c", "\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.tostring()
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 # Reading after iteration hit EOF shouldn't hurt either
298 f = open(TESTFN)
299 try:
300 for line in f:
301 pass
302 try:
303 f.readline()
304 f.readinto(buf)
305 f.read()
306 f.readlines()
307 except ValueError:
308 self.fail("read* failed after next() consumed file")
309 finally:
310 f.close()
311 finally:
312 os.unlink(TESTFN)
313
314
315def test_main():
316 run_unittest(AutoFileTests, OtherFileTests)
317
318if __name__ == '__main__':
319 test_main()