blob: fe3bb922a986f0d425c1914a26926642ee5ad8ed [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()
Tim Peters0556e9b2006-06-09 04:02:06 +0000138 os.unlink(TESTFN)
Thomas Woutersc45251a2006-02-12 11:53:32 +0000139
Georg Brandl442b49e2006-06-08 14:50:53 +0000140 def testBadModeArgument(self):
141 # verify that we get a sensible error message for bad mode argument
142 bad_mode = "qwerty"
Tim Peterscffcfed2006-02-14 17:41:18 +0000143 try:
Georg Brandl442b49e2006-06-08 14:50:53 +0000144 f = open(TESTFN, bad_mode)
145 except ValueError, msg:
146 if msg[0] != 0:
147 s = str(msg)
148 if s.find(TESTFN) != -1 or s.find(bad_mode) == -1:
149 self.fail("bad error message for invalid mode: %s" % s)
150 # if msg[0] == 0, we're probably on Windows where there may be
151 # no obvious way to discover why open() failed.
152 else:
153 f.close()
154 self.fail("no error for invalid mode: %s" % bad_mode)
155
156 def testSetBufferSize(self):
157 # make sure that explicitly setting the buffer size doesn't cause
158 # misbehaviour especially with repeated close() calls
159 for s in (-1, 0, 1, 512):
160 try:
161 f = open(TESTFN, 'w', s)
162 f.write(str(s))
163 f.close()
164 f.close()
165 f = open(TESTFN, 'r', s)
166 d = int(f.read())
167 f.close()
168 f.close()
169 except IOError, msg:
170 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
171 self.assertEquals(d, s)
172
173 def testTruncateOnWindows(self):
174 os.unlink(TESTFN)
175
176 def bug801631():
177 # SF bug <http://www.python.org/sf/801631>
178 # "file.truncate fault on windows"
Tim Petersdbb82f62006-06-09 03:51:41 +0000179 f = open(TESTFN, 'wb')
Georg Brandl442b49e2006-06-08 14:50:53 +0000180 f.write('12345678901') # 11 bytes
181 f.close()
182
Tim Petersdbb82f62006-06-09 03:51:41 +0000183 f = open(TESTFN,'rb+')
Georg Brandl442b49e2006-06-08 14:50:53 +0000184 data = f.read(5)
185 if data != '12345':
186 self.fail("Read on file opened for update failed %r" % data)
187 if f.tell() != 5:
188 self.fail("File pos after read wrong %d" % f.tell())
189
190 f.truncate()
191 if f.tell() != 5:
192 self.fail("File pos after ftruncate wrong %d" % f.tell())
193
194 f.close()
195 size = os.path.getsize(TESTFN)
196 if size != 5:
197 self.fail("File size after ftruncate wrong %d" % size)
198
199 try:
200 bug801631()
201 finally:
202 os.unlink(TESTFN)
203
204 def testIteration(self):
Tim Petersdbb82f62006-06-09 03:51:41 +0000205 # Test the complex interaction when mixing file-iteration and the
206 # various read* methods. Ostensibly, the mixture could just be tested
207 # to work when it should work according to the Python language,
208 # instead of fail when it should fail according to the current CPython
209 # implementation. People don't always program Python the way they
210 # should, though, and the implemenation might change in subtle ways,
211 # so we explicitly test for errors, too; the test will just have to
212 # be updated when the implementation changes.
Georg Brandl442b49e2006-06-08 14:50:53 +0000213 dataoffset = 16384
214 filler = "ham\n"
215 assert not dataoffset % len(filler), \
216 "dataoffset must be multiple of len(filler)"
217 nchunks = dataoffset // len(filler)
218 testlines = [
219 "spam, spam and eggs\n",
220 "eggs, spam, ham and spam\n",
221 "saussages, spam, spam and eggs\n",
222 "spam, ham, spam and eggs\n",
223 "spam, spam, spam, spam, spam, ham, spam\n",
224 "wonderful spaaaaaam.\n"
225 ]
226 methods = [("readline", ()), ("read", ()), ("readlines", ()),
227 ("readinto", (array("c", " "*100),))]
228
229 try:
230 # Prepare the testfile
231 bag = open(TESTFN, "w")
232 bag.write(filler * nchunks)
233 bag.writelines(testlines)
234 bag.close()
235 # Test for appropriate errors mixing read* and iteration
236 for methodname, args in methods:
237 f = open(TESTFN)
238 if f.next() != filler:
239 self.fail, "Broken testfile"
240 meth = getattr(f, methodname)
241 try:
242 meth(*args)
243 except ValueError:
244 pass
245 else:
246 self.fail("%s%r after next() didn't raise ValueError" %
247 (methodname, args))
248 f.close()
249
Tim Petersdbb82f62006-06-09 03:51:41 +0000250 # Test to see if harmless (by accident) mixing of read* and
251 # iteration still works. This depends on the size of the internal
252 # iteration buffer (currently 8192,) but we can test it in a
253 # flexible manner. Each line in the bag o' ham is 4 bytes
254 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
255 # exactly on the buffer boundary for any power-of-2 buffersize
256 # between 4 and 16384 (inclusive).
Georg Brandl442b49e2006-06-08 14:50:53 +0000257 f = open(TESTFN)
258 for i in range(nchunks):
259 f.next()
260 testline = testlines.pop(0)
261 try:
262 line = f.readline()
263 except ValueError:
264 self.fail("readline() after next() with supposedly empty "
265 "iteration-buffer failed anyway")
266 if line != testline:
267 self.fail("readline() after next() with empty buffer "
268 "failed. Got %r, expected %r" % (line, testline))
269 testline = testlines.pop(0)
270 buf = array("c", "\x00" * len(testline))
271 try:
272 f.readinto(buf)
273 except ValueError:
274 self.fail("readinto() after next() with supposedly empty "
275 "iteration-buffer failed anyway")
276 line = buf.tostring()
277 if line != testline:
278 self.fail("readinto() after next() with empty buffer "
279 "failed. Got %r, expected %r" % (line, testline))
280
281 testline = testlines.pop(0)
282 try:
283 line = f.read(len(testline))
284 except ValueError:
285 self.fail("read() after next() with supposedly empty "
286 "iteration-buffer failed anyway")
287 if line != testline:
288 self.fail("read() after next() with empty buffer "
289 "failed. Got %r, expected %r" % (line, testline))
290 try:
291 lines = f.readlines()
292 except ValueError:
293 self.fail("readlines() after next() with supposedly empty "
294 "iteration-buffer failed anyway")
295 if lines != testlines:
296 self.fail("readlines() after next() with empty buffer "
297 "failed. Got %r, expected %r" % (line, testline))
298 # Reading after iteration hit EOF shouldn't hurt either
299 f = open(TESTFN)
300 try:
301 for line in f:
302 pass
303 try:
304 f.readline()
305 f.readinto(buf)
306 f.read()
307 f.readlines()
308 except ValueError:
309 self.fail("read* failed after next() consumed file")
310 finally:
311 f.close()
312 finally:
313 os.unlink(TESTFN)
314
315
316def test_main():
Tim Peters0556e9b2006-06-09 04:02:06 +0000317 # Historically, these tests have sloppy about removing TESTFN. So get
318 # rid of it no matter what.
319 try:
320 run_unittest(AutoFileTests, OtherFileTests)
321 finally:
322 if os.path.exists(TESTFN):
323 os.unlink(TESTFN)
Georg Brandl442b49e2006-06-08 14:50:53 +0000324
325if __name__ == '__main__':
326 test_main()