blob: aee7c3640ffad3ed3f4d6b14acf86a770ebdc80d [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):
14 self.f = file(TESTFN, 'wb')
Tim Peters015dd822003-05-04 04:16:52 +000015
Georg Brandl442b49e2006-06-08 14:50:53 +000016 def tearDown(self):
Thomas Woutersc45251a2006-02-12 11:53:32 +000017 try:
Georg Brandl442b49e2006-06-08 14:50:53 +000018 if self.f:
19 self.f.close()
20 except IOError:
Thomas Woutersc45251a2006-02-12 11:53:32 +000021 pass
Georg Brandl442b49e2006-06-08 14:50:53 +000022
23 def testWeakRefs(self):
24 # verify weak references
25 p = proxy(self.f)
26 p.write('teststring')
27 self.assertEquals(self.f.tell(), p.tell())
28 self.f.close()
29 self.f = None
30 self.assertRaises(ReferenceError, getattr, p, 'tell')
31
32 def testAttributes(self):
33 # verify expected attributes exist
34 f = self.f
35 softspace = f.softspace
36 f.name # merely shouldn't blow up
37 f.mode # ditto
38 f.closed # ditto
39
40 # verify softspace is writable
41 f.softspace = softspace # merely shouldn't blow up
42
43 # verify the others aren't
44 for attr in 'name', 'mode', 'closed':
45 self.assertRaises((AttributeError, TypeError), setattr, f, attr, 'oops')
46
47 def testReadinto(self):
48 # verify readinto
49 self.f.write('12')
50 self.f.close()
51 a = array('c', 'x'*10)
52 self.f = open(TESTFN, 'rb')
53 n = self.f.readinto(a)
54 self.assertEquals('12', a.tostring()[:n])
55
56 def testWritelinesUserList(self):
57 # verify writelines with instance sequence
58 l = UserList(['1', '2'])
59 self.f.writelines(l)
60 self.f.close()
61 self.f = open(TESTFN, 'rb')
62 buf = self.f.read()
63 self.assertEquals(buf, '12')
64
65 def testWritelinesIntegers(self):
66 # verify writelines with integers
67 self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
68
69 def testWritelinesIntegersUserList(self):
70 # verify writelines with integers in UserList
71 l = UserList([1,2,3])
72 self.assertRaises(TypeError, self.f.writelines, l)
73
74 def testWritelinesNonString(self):
75 # verify writelines with non-string object
76 class NonString: pass
77
78 self.assertRaises(TypeError, self.f.writelines, [NonString(), NonString()])
79
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',
96 'readline', 'readlines', 'seek', 'tell', 'truncate', 'write',
97 'xreadlines', '__iter__']
98 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:
116 f = file(TESTFN, mode)
117 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"
178 f = file(TESTFN, 'wb')
179 f.write('12345678901') # 11 bytes
180 f.close()
181
182 f = file(TESTFN,'rb+')
183 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):
204 # Test the complex interaction when mixing file-iteration and the various
205 # read* methods. Ostensibly, the mixture could just be tested to work
206 # when it should work according to the Python language, instead of fail
207 # when it should fail according to the current CPython implementation.
208 # People don't always program Python the way they should, though, and the
209 # implemenation might change in subtle ways, so we explicitly test for
210 # errors, too; the test will just have to be updated when the
211 # implementation changes.
212 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
249 # Test to see if harmless (by accident) mixing of read* and iteration
250 # still works. This depends on the size of the internal iteration
251 # buffer (currently 8192,) but we can test it in a flexible manner.
252 # Each line in the bag o' ham is 4 bytes ("h", "a", "m", "\n"), so
253 # 4096 lines of that should get us exactly on the buffer boundary for
254 # any power-of-2 buffersize between 4 and 16384 (inclusive).
255 f = open(TESTFN)
256 for i in range(nchunks):
257 f.next()
258 testline = testlines.pop(0)
259 try:
260 line = f.readline()
261 except ValueError:
262 self.fail("readline() after next() with supposedly empty "
263 "iteration-buffer failed anyway")
264 if line != testline:
265 self.fail("readline() after next() with empty buffer "
266 "failed. Got %r, expected %r" % (line, testline))
267 testline = testlines.pop(0)
268 buf = array("c", "\x00" * len(testline))
269 try:
270 f.readinto(buf)
271 except ValueError:
272 self.fail("readinto() after next() with supposedly empty "
273 "iteration-buffer failed anyway")
274 line = buf.tostring()
275 if line != testline:
276 self.fail("readinto() after next() with empty buffer "
277 "failed. Got %r, expected %r" % (line, testline))
278
279 testline = testlines.pop(0)
280 try:
281 line = f.read(len(testline))
282 except ValueError:
283 self.fail("read() after next() with supposedly empty "
284 "iteration-buffer failed anyway")
285 if line != testline:
286 self.fail("read() after next() with empty buffer "
287 "failed. Got %r, expected %r" % (line, testline))
288 try:
289 lines = f.readlines()
290 except ValueError:
291 self.fail("readlines() after next() with supposedly empty "
292 "iteration-buffer failed anyway")
293 if lines != testlines:
294 self.fail("readlines() after next() with empty buffer "
295 "failed. Got %r, expected %r" % (line, testline))
296 # Reading after iteration hit EOF shouldn't hurt either
297 f = open(TESTFN)
298 try:
299 for line in f:
300 pass
301 try:
302 f.readline()
303 f.readinto(buf)
304 f.read()
305 f.readlines()
306 except ValueError:
307 self.fail("read* failed after next() consumed file")
308 finally:
309 f.close()
310 finally:
311 os.unlink(TESTFN)
312
313
314def test_main():
315 run_unittest(AutoFileTests, OtherFileTests)
316
317if __name__ == '__main__':
318 test_main()