move sections
[python/dscho.git] / Lib / test / test_file.py
blobc3c0defa51ea4cb64a01d142d0221711fcaf51ae
1 # NOTE: this file tests the new `io` library backported from Python 3.x.
2 # Similar tests for the builtin file object can be found in test_file2k.py.
4 from __future__ import print_function
6 import sys
7 import os
8 import unittest
9 from array import array
10 from weakref import proxy
12 import io
13 import _pyio as pyio
15 from test.test_support import TESTFN, run_unittest
16 from UserList import UserList
18 class AutoFileTests(unittest.TestCase):
19 # file tests for which a test file is automatically set up
21 def setUp(self):
22 self.f = self.open(TESTFN, 'wb')
24 def tearDown(self):
25 if self.f:
26 self.f.close()
27 os.remove(TESTFN)
29 def testWeakRefs(self):
30 # verify weak references
31 p = proxy(self.f)
32 p.write(b'teststring')
33 self.assertEquals(self.f.tell(), p.tell())
34 self.f.close()
35 self.f = None
36 self.assertRaises(ReferenceError, getattr, p, 'tell')
38 def testAttributes(self):
39 # verify expected attributes exist
40 f = self.f
41 f.name # merely shouldn't blow up
42 f.mode # ditto
43 f.closed # ditto
45 def testReadinto(self):
46 # verify readinto
47 self.f.write(b'12')
48 self.f.close()
49 a = array('b', b'x'*10)
50 self.f = self.open(TESTFN, 'rb')
51 n = self.f.readinto(a)
52 self.assertEquals(b'12', a.tostring()[:n])
54 def testReadinto_text(self):
55 # verify readinto refuses text files
56 a = array('b', b'x'*10)
57 self.f.close()
58 self.f = self.open(TESTFN, 'r')
59 if hasattr(self.f, "readinto"):
60 self.assertRaises(TypeError, self.f.readinto, a)
62 def testWritelinesUserList(self):
63 # verify writelines with instance sequence
64 l = UserList([b'1', b'2'])
65 self.f.writelines(l)
66 self.f.close()
67 self.f = self.open(TESTFN, 'rb')
68 buf = self.f.read()
69 self.assertEquals(buf, b'12')
71 def testWritelinesIntegers(self):
72 # verify writelines with integers
73 self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
75 def testWritelinesIntegersUserList(self):
76 # verify writelines with integers in UserList
77 l = UserList([1,2,3])
78 self.assertRaises(TypeError, self.f.writelines, l)
80 def testWritelinesNonString(self):
81 # verify writelines with non-string object
82 class NonString:
83 pass
85 self.assertRaises(TypeError, self.f.writelines,
86 [NonString(), NonString()])
88 def testErrors(self):
89 f = self.f
90 self.assertEquals(f.name, TESTFN)
91 self.assertTrue(not f.isatty())
92 self.assertTrue(not f.closed)
94 if hasattr(f, "readinto"):
95 self.assertRaises((IOError, TypeError), f.readinto, "")
96 f.close()
97 self.assertTrue(f.closed)
99 def testMethods(self):
100 methods = [('fileno', ()),
101 ('flush', ()),
102 ('isatty', ()),
103 ('next', ()),
104 ('read', ()),
105 ('write', (b"",)),
106 ('readline', ()),
107 ('readlines', ()),
108 ('seek', (0,)),
109 ('tell', ()),
110 ('write', (b"",)),
111 ('writelines', ([],)),
112 ('__iter__', ()),
114 if not sys.platform.startswith('atheos'):
115 methods.append(('truncate', ()))
117 # __exit__ should close the file
118 self.f.__exit__(None, None, None)
119 self.assertTrue(self.f.closed)
121 for methodname, args in methods:
122 method = getattr(self.f, methodname)
123 # should raise on closed file
124 self.assertRaises(ValueError, method, *args)
126 # file is closed, __exit__ shouldn't do anything
127 self.assertEquals(self.f.__exit__(None, None, None), None)
128 # it must also return None if an exception was given
129 try:
130 1 // 0
131 except:
132 self.assertEquals(self.f.__exit__(*sys.exc_info()), None)
134 def testReadWhenWriting(self):
135 self.assertRaises(IOError, self.f.read)
137 class CAutoFileTests(AutoFileTests):
138 open = io.open
140 class PyAutoFileTests(AutoFileTests):
141 open = staticmethod(pyio.open)
144 class OtherFileTests(unittest.TestCase):
146 def testModeStrings(self):
147 # check invalid mode strings
148 for mode in ("", "aU", "wU+"):
149 try:
150 f = self.open(TESTFN, mode)
151 except ValueError:
152 pass
153 else:
154 f.close()
155 self.fail('%r is an invalid file mode' % mode)
157 def testStdin(self):
158 # This causes the interpreter to exit on OSF1 v5.1.
159 if sys.platform != 'osf1V5':
160 self.assertRaises((IOError, ValueError), sys.stdin.seek, -1)
161 else:
162 print((
163 ' Skipping sys.stdin.seek(-1), it may crash the interpreter.'
164 ' Test manually.'), file=sys.__stdout__)
165 self.assertRaises((IOError, ValueError), sys.stdin.truncate)
167 def testBadModeArgument(self):
168 # verify that we get a sensible error message for bad mode argument
169 bad_mode = "qwerty"
170 try:
171 f = self.open(TESTFN, bad_mode)
172 except ValueError as msg:
173 if msg.args[0] != 0:
174 s = str(msg)
175 if TESTFN in s or bad_mode not in s:
176 self.fail("bad error message for invalid mode: %s" % s)
177 # if msg.args[0] == 0, we're probably on Windows where there may be
178 # no obvious way to discover why open() failed.
179 else:
180 f.close()
181 self.fail("no error for invalid mode: %s" % bad_mode)
183 def testSetBufferSize(self):
184 # make sure that explicitly setting the buffer size doesn't cause
185 # misbehaviour especially with repeated close() calls
186 for s in (-1, 0, 1, 512):
187 try:
188 f = self.open(TESTFN, 'wb', s)
189 f.write(str(s).encode("ascii"))
190 f.close()
191 f.close()
192 f = self.open(TESTFN, 'rb', s)
193 d = int(f.read().decode("ascii"))
194 f.close()
195 f.close()
196 except IOError as msg:
197 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
198 self.assertEquals(d, s)
200 def testTruncateOnWindows(self):
201 # SF bug <http://www.python.org/sf/801631>
202 # "file.truncate fault on windows"
204 os.unlink(TESTFN)
205 f = self.open(TESTFN, 'wb')
207 try:
208 f.write(b'12345678901') # 11 bytes
209 f.close()
211 f = self.open(TESTFN,'rb+')
212 data = f.read(5)
213 if data != b'12345':
214 self.fail("Read on file opened for update failed %r" % data)
215 if f.tell() != 5:
216 self.fail("File pos after read wrong %d" % f.tell())
218 f.truncate()
219 if f.tell() != 5:
220 self.fail("File pos after ftruncate wrong %d" % f.tell())
222 f.close()
223 size = os.path.getsize(TESTFN)
224 if size != 5:
225 self.fail("File size after ftruncate wrong %d" % size)
226 finally:
227 f.close()
228 os.unlink(TESTFN)
230 def testIteration(self):
231 # Test the complex interaction when mixing file-iteration and the
232 # various read* methods.
233 dataoffset = 16384
234 filler = b"ham\n"
235 assert not dataoffset % len(filler), \
236 "dataoffset must be multiple of len(filler)"
237 nchunks = dataoffset // len(filler)
238 testlines = [
239 b"spam, spam and eggs\n",
240 b"eggs, spam, ham and spam\n",
241 b"saussages, spam, spam and eggs\n",
242 b"spam, ham, spam and eggs\n",
243 b"spam, spam, spam, spam, spam, ham, spam\n",
244 b"wonderful spaaaaaam.\n"
246 methods = [("readline", ()), ("read", ()), ("readlines", ()),
247 ("readinto", (array("b", b" "*100),))]
249 try:
250 # Prepare the testfile
251 bag = self.open(TESTFN, "wb")
252 bag.write(filler * nchunks)
253 bag.writelines(testlines)
254 bag.close()
255 # Test for appropriate errors mixing read* and iteration
256 for methodname, args in methods:
257 f = self.open(TESTFN, 'rb')
258 if next(f) != filler:
259 self.fail, "Broken testfile"
260 meth = getattr(f, methodname)
261 meth(*args) # This simply shouldn't fail
262 f.close()
264 # Test to see if harmless (by accident) mixing of read* and
265 # iteration still works. This depends on the size of the internal
266 # iteration buffer (currently 8192,) but we can test it in a
267 # flexible manner. Each line in the bag o' ham is 4 bytes
268 # ("h", "a", "m", "\n"), so 4096 lines of that should get us
269 # exactly on the buffer boundary for any power-of-2 buffersize
270 # between 4 and 16384 (inclusive).
271 f = self.open(TESTFN, 'rb')
272 for i in range(nchunks):
273 next(f)
274 testline = testlines.pop(0)
275 try:
276 line = f.readline()
277 except ValueError:
278 self.fail("readline() after next() with supposedly empty "
279 "iteration-buffer failed anyway")
280 if line != testline:
281 self.fail("readline() after next() with empty buffer "
282 "failed. Got %r, expected %r" % (line, testline))
283 testline = testlines.pop(0)
284 buf = array("b", b"\x00" * len(testline))
285 try:
286 f.readinto(buf)
287 except ValueError:
288 self.fail("readinto() after next() with supposedly empty "
289 "iteration-buffer failed anyway")
290 line = buf.tostring()
291 if line != testline:
292 self.fail("readinto() after next() with empty buffer "
293 "failed. Got %r, expected %r" % (line, testline))
295 testline = testlines.pop(0)
296 try:
297 line = f.read(len(testline))
298 except ValueError:
299 self.fail("read() after next() with supposedly empty "
300 "iteration-buffer failed anyway")
301 if line != testline:
302 self.fail("read() after next() with empty buffer "
303 "failed. Got %r, expected %r" % (line, testline))
304 try:
305 lines = f.readlines()
306 except ValueError:
307 self.fail("readlines() after next() with supposedly empty "
308 "iteration-buffer failed anyway")
309 if lines != testlines:
310 self.fail("readlines() after next() with empty buffer "
311 "failed. Got %r, expected %r" % (line, testline))
312 # Reading after iteration hit EOF shouldn't hurt either
313 f = self.open(TESTFN, 'rb')
314 try:
315 for line in f:
316 pass
317 try:
318 f.readline()
319 f.readinto(buf)
320 f.read()
321 f.readlines()
322 except ValueError:
323 self.fail("read* failed after next() consumed file")
324 finally:
325 f.close()
326 finally:
327 os.unlink(TESTFN)
329 class COtherFileTests(OtherFileTests):
330 open = io.open
332 class PyOtherFileTests(OtherFileTests):
333 open = staticmethod(pyio.open)
336 def test_main():
337 # Historically, these tests have been sloppy about removing TESTFN.
338 # So get rid of it no matter what.
339 try:
340 run_unittest(CAutoFileTests, PyAutoFileTests,
341 COtherFileTests, PyOtherFileTests)
342 finally:
343 if os.path.exists(TESTFN):
344 os.unlink(TESTFN)
346 if __name__ == '__main__':
347 test_main()