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
9 from array
import array
10 from weakref
import proxy
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
22 self
.f
= self
.open(TESTFN
, 'wb')
29 def testWeakRefs(self
):
30 # verify weak references
32 p
.write(b
'teststring')
33 self
.assertEquals(self
.f
.tell(), p
.tell())
36 self
.assertRaises(ReferenceError, getattr, p
, 'tell')
38 def testAttributes(self
):
39 # verify expected attributes exist
41 f
.name
# merely shouldn't blow up
45 def testReadinto(self
):
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)
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'])
67 self
.f
= self
.open(TESTFN
, 'rb')
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
78 self
.assertRaises(TypeError, self
.f
.writelines
, l
)
80 def testWritelinesNonString(self
):
81 # verify writelines with non-string object
85 self
.assertRaises(TypeError, self
.f
.writelines
,
86 [NonString(), NonString()])
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
, "")
97 self
.assertTrue(f
.closed
)
99 def testMethods(self
):
100 methods
= [('fileno', ()),
111 ('writelines', ([],)),
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
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
):
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+"):
150 f
= self
.open(TESTFN
, mode
)
155 self
.fail('%r is an invalid file mode' % mode
)
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)
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
171 f
= self
.open(TESTFN
, bad_mode
)
172 except ValueError as 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.
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):
188 f
= self
.open(TESTFN
, 'wb', s
)
189 f
.write(str(s
).encode("ascii"))
192 f
= self
.open(TESTFN
, 'rb', s
)
193 d
= int(f
.read().decode("ascii"))
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"
205 f
= self
.open(TESTFN
, 'wb')
208 f
.write(b
'12345678901') # 11 bytes
211 f
= self
.open(TESTFN
,'rb+')
214 self
.fail("Read on file opened for update failed %r" % data
)
216 self
.fail("File pos after read wrong %d" % f
.tell())
220 self
.fail("File pos after ftruncate wrong %d" % f
.tell())
223 size
= os
.path
.getsize(TESTFN
)
225 self
.fail("File size after ftruncate wrong %d" % size
)
230 def testIteration(self
):
231 # Test the complex interaction when mixing file-iteration and the
232 # various read* methods.
235 assert not dataoffset
% len(filler
), \
236 "dataoffset must be multiple of len(filler)"
237 nchunks
= dataoffset
// len(filler
)
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),))]
250 # Prepare the testfile
251 bag
= self
.open(TESTFN
, "wb")
252 bag
.write(filler
* nchunks
)
253 bag
.writelines(testlines
)
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
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
):
274 testline
= testlines
.pop(0)
278 self
.fail("readline() after next() with supposedly empty "
279 "iteration-buffer failed anyway")
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
))
288 self
.fail("readinto() after next() with supposedly empty "
289 "iteration-buffer failed anyway")
290 line
= buf
.tostring()
292 self
.fail("readinto() after next() with empty buffer "
293 "failed. Got %r, expected %r" % (line
, testline
))
295 testline
= testlines
.pop(0)
297 line
= f
.read(len(testline
))
299 self
.fail("read() after next() with supposedly empty "
300 "iteration-buffer failed anyway")
302 self
.fail("read() after next() with empty buffer "
303 "failed. Got %r, expected %r" % (line
, testline
))
305 lines
= f
.readlines()
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')
323 self
.fail("read* failed after next() consumed file")
329 class COtherFileTests(OtherFileTests
):
332 class PyOtherFileTests(OtherFileTests
):
333 open = staticmethod(pyio
.open)
337 # Historically, these tests have been sloppy about removing TESTFN.
338 # So get rid of it no matter what.
340 run_unittest(CAutoFileTests
, PyAutoFileTests
,
341 COtherFileTests
, PyOtherFileTests
)
343 if os
.path
.exists(TESTFN
):
346 if __name__
== '__main__':