blob: dcfa265508d71fb83079060065a505cdbb15f550 [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):
14 self.f = file(TESTFN, 'wb')
Tim Peters015dd822003-05-04 04:16:52 +000015
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000016 def tearDown(self):
Thomas Woutersc45251a2006-02-12 11:53:32 +000017 try:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +000018 if self.f:
19 self.f.close()
20 except IOError:
Thomas Woutersc45251a2006-02-12 11:53:32 +000021 pass
Thomas Wouters73e5a5b2006-06-08 15:35:45 +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 testReadinto_text(self):
57 # verify readinto refuses text files
58 a = array('c', 'x'*10)
59 self.f.close()
60 self.f = open(TESTFN, 'r')
61 self.assertRaises(TypeError, self.f.readinto, a)
62
63 def testWritelinesUserList(self):
64 # verify writelines with instance sequence
65 l = UserList(['1', '2'])
66 self.f.writelines(l)
67 self.f.close()
68 self.f = open(TESTFN, 'rb')
69 buf = self.f.read()
70 self.assertEquals(buf, '12')
71
72 def testWritelinesIntegers(self):
73 # verify writelines with integers
74 self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
75
76 def testWritelinesIntegersUserList(self):
77 # verify writelines with integers in UserList
78 l = UserList([1,2,3])
79 self.assertRaises(TypeError, self.f.writelines, l)
80
81 def testWritelinesNonString(self):
82 # verify writelines with non-string object
83 class NonString: pass
84
85 self.assertRaises(TypeError, self.f.writelines, [NonString(), NonString()])
86
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)
96
97 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',
103 'readline', 'readlines', 'seek', 'tell', 'truncate', 'write',
104 '__iter__']
105 if sys.platform.startswith('atheos'):
106 methods.remove('truncate')
107
108 self.f.close()
109
110 for methodname in methods:
111 method = getattr(self.f, methodname)
112 # should raise on closed file
113 self.assertRaises(ValueError, method)
114 self.assertRaises(ValueError, self.f.writelines, [])
115
116
117class OtherFileTests(unittest.TestCase):
118
119 def testModeStrings(self):
120 # check invalid mode strings
121 for mode in ("", "aU", "wU+"):
122 try:
123 f = file(TESTFN, mode)
124 except ValueError:
125 pass
126 else:
127 f.close()
128 self.fail('%r is an invalid file mode' % mode)
129
130 def testStdin(self):
131 # This causes the interpreter to exit on OSF1 v5.1.
132 if sys.platform != 'osf1V5':
133 self.assertRaises(IOError, sys.stdin.seek, -1)
Thomas Woutersc45251a2006-02-12 11:53:32 +0000134 else:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000135 print >>sys.__stdout__, (
136 ' Skipping sys.stdin.seek(-1), it may crash the interpreter.'
137 ' Test manually.')
138 self.assertRaises(IOError, sys.stdin.truncate)
139
140 def testUnicodeOpen(self):
141 # verify repr works for unicode too
142 f = open(unicode(TESTFN), "w")
143 self.assert_(repr(f).startswith("<open file u'" + TESTFN))
Thomas Woutersc45251a2006-02-12 11:53:32 +0000144 f.close()
145
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000146 def testBadModeArgument(self):
147 # verify that we get a sensible error message for bad mode argument
148 bad_mode = "qwerty"
Tim Peterscffcfed2006-02-14 17:41:18 +0000149 try:
Thomas Wouters73e5a5b2006-06-08 15:35:45 +0000150 f = open(TESTFN, bad_mode)
151 except ValueError, msg:
152 if msg[0] != 0:
153 s = str(msg)
154 if s.find(TESTFN) != -1 or s.find(bad_mode) == -1:
155 self.fail("bad error message for invalid mode: %s" % s)
156 # if msg[0] == 0, we're probably on Windows where there may be
157 # no obvious way to discover why open() failed.
158 else:
159 f.close()
160 self.fail("no error for invalid mode: %s" % bad_mode)
161
162 def testSetBufferSize(self):
163 # make sure that explicitly setting the buffer size doesn't cause
164 # misbehaviour especially with repeated close() calls
165 for s in (-1, 0, 1, 512):
166 try:
167 f = open(TESTFN, 'w', s)
168 f.write(str(s))
169 f.close()
170 f.close()
171 f = open(TESTFN, 'r', s)
172 d = int(f.read())
173 f.close()
174 f.close()
175 except IOError, msg:
176 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
177 self.assertEquals(d, s)
178
179 def testTruncateOnWindows(self):
180 os.unlink(TESTFN)
181
182 def bug801631():
183 # SF bug <http://www.python.org/sf/801631>
184 # "file.truncate fault on windows"
185 f = file(TESTFN, 'wb')
186 f.write('12345678901') # 11 bytes
187 f.close()
188
189 f = file(TESTFN,'rb+')
190 data = f.read(5)
191 if data != '12345':
192 self.fail("Read on file opened for update failed %r" % data)
193 if f.tell() != 5:
194 self.fail("File pos after read wrong %d" % f.tell())
195
196 f.truncate()
197 if f.tell() != 5:
198 self.fail("File pos after ftruncate wrong %d" % f.tell())
199
200 f.close()
201 size = os.path.getsize(TESTFN)
202 if size != 5:
203 self.fail("File size after ftruncate wrong %d" % size)
204
205 try:
206 bug801631()
207 finally:
208 os.unlink(TESTFN)
209
210 def testIteration(self):
211 # Test the complex interaction when mixing file-iteration and the various
212 # read* methods. Ostensibly, the mixture could just be tested to work
213 # when it should work according to the Python language, instead of fail
214 # when it should fail according to the current CPython implementation.
215 # People don't always program Python the way they should, though, and the
216 # implemenation might change in subtle ways, so we explicitly test for
217 # errors, too; the test will just have to be updated when the
218 # implementation changes.
219 dataoffset = 16384
220 filler = "ham\n"
221 assert not dataoffset % len(filler), \
222 "dataoffset must be multiple of len(filler)"
223 nchunks = dataoffset // len(filler)
224 testlines = [
225 "spam, spam and eggs\n",
226 "eggs, spam, ham and spam\n",
227 "saussages, spam, spam and eggs\n",
228 "spam, ham, spam and eggs\n",
229 "spam, spam, spam, spam, spam, ham, spam\n",
230 "wonderful spaaaaaam.\n"
231 ]
232 methods = [("readline", ()), ("read", ()), ("readlines", ()),
233 ("readinto", (array("c", " "*100),))]
234
235 try:
236 # Prepare the testfile
237 bag = open(TESTFN, "wb")
238 bag.write(filler * nchunks)
239 bag.writelines(testlines)
240 bag.close()
241 # Test for appropriate errors mixing read* and iteration
242 for methodname, args in methods:
243 f = open(TESTFN, 'rb')
244 if f.next() != filler:
245 self.fail, "Broken testfile"
246 meth = getattr(f, methodname)
247 try:
248 meth(*args)
249 except ValueError:
250 pass
251 else:
252 self.fail("%s%r after next() didn't raise ValueError" %
253 (methodname, args))
254 f.close()
255
256 # Test to see if harmless (by accident) mixing of read* and iteration
257 # still works. This depends on the size of the internal iteration
258 # buffer (currently 8192,) but we can test it in a flexible manner.
259 # Each line in the bag o' ham is 4 bytes ("h", "a", "m", "\n"), so
260 # 4096 lines of that should get us exactly on the buffer boundary for
261 # any power-of-2 buffersize between 4 and 16384 (inclusive).
262 f = open(TESTFN, 'rb')
263 for i in range(nchunks):
264 f.next()
265 testline = testlines.pop(0)
266 try:
267 line = f.readline()
268 except ValueError:
269 self.fail("readline() after next() with supposedly empty "
270 "iteration-buffer failed anyway")
271 if line != testline:
272 self.fail("readline() after next() with empty buffer "
273 "failed. Got %r, expected %r" % (line, testline))
274 testline = testlines.pop(0)
275 buf = array("c", "\x00" * len(testline))
276 try:
277 f.readinto(buf)
278 except ValueError:
279 self.fail("readinto() after next() with supposedly empty "
280 "iteration-buffer failed anyway")
281 line = buf.tostring()
282 if line != testline:
283 self.fail("readinto() after next() with empty buffer "
284 "failed. Got %r, expected %r" % (line, testline))
285
286 testline = testlines.pop(0)
287 try:
288 line = f.read(len(testline))
289 except ValueError:
290 self.fail("read() after next() with supposedly empty "
291 "iteration-buffer failed anyway")
292 if line != testline:
293 self.fail("read() after next() with empty buffer "
294 "failed. Got %r, expected %r" % (line, testline))
295 try:
296 lines = f.readlines()
297 except ValueError:
298 self.fail("readlines() after next() with supposedly empty "
299 "iteration-buffer failed anyway")
300 if lines != testlines:
301 self.fail("readlines() after next() with empty buffer "
302 "failed. Got %r, expected %r" % (line, testline))
303 # Reading after iteration hit EOF shouldn't hurt either
304 f = open(TESTFN, 'rb')
305 try:
306 for line in f:
307 pass
308 try:
309 f.readline()
310 f.readinto(buf)
311 f.read()
312 f.readlines()
313 except ValueError:
314 self.fail("read* failed after next() consumed file")
315 finally:
316 f.close()
317 finally:
318 os.unlink(TESTFN)
319
320
321def test_main():
322 run_unittest(AutoFileTests, OtherFileTests)
323
324if __name__ == '__main__':
325 test_main()