test_file.py 11 KB

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