Issue #6215: backport the 3.1 io lib
diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
index 928fbec..e8d6362 100644
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -1,23 +1,26 @@
 # Adapted from test_file.py by Daniel Stutzbach
-#from __future__ import unicode_literals
+
+from __future__ import unicode_literals
 
 import sys
 import os
+import errno
 import unittest
 from array import array
 from weakref import proxy
+from functools import wraps
 
 from test.test_support import (TESTFN, findfile, check_warnings, run_unittest,
                                make_bad_fd)
-from UserList import UserList
+from test.test_support import py3k_bytes as bytes
 
-import _fileio
+from _io import FileIO as _FileIO
 
 class AutoFileTests(unittest.TestCase):
     # file tests for which a test file is automatically set up
 
     def setUp(self):
-        self.f = _fileio._FileIO(TESTFN, 'w')
+        self.f = _FileIO(TESTFN, 'w')
 
     def tearDown(self):
         if self.f:
@@ -34,7 +37,7 @@
         self.assertRaises(ReferenceError, getattr, p, 'tell')
 
     def testSeekTell(self):
-        self.f.write(bytes(bytearray(range(20))))
+        self.f.write(bytes(range(20)))
         self.assertEquals(self.f.tell(), 20)
         self.f.seek(0)
         self.assertEquals(self.f.tell(), 0)
@@ -61,17 +64,21 @@
 
     def testReadinto(self):
         # verify readinto
-        self.f.write(bytes(bytearray([1, 2])))
+        self.f.write(b"\x01\x02")
         self.f.close()
-        a = array('b', b'x'*10)
-        self.f = _fileio._FileIO(TESTFN, 'r')
+        a = array(b'b', b'x'*10)
+        self.f = _FileIO(TESTFN, 'r')
         n = self.f.readinto(a)
-        self.assertEquals(array('b', [1, 2]), a[:n])
+        self.assertEquals(array(b'b', [1, 2]), a[:n])
 
     def testRepr(self):
-        self.assertEquals(repr(self.f),
-                          "_fileio._FileIO(%d, %s)" % (self.f.fileno(),
-                                                       repr(self.f.mode)))
+        self.assertEquals(repr(self.f), "<_io.FileIO name=%r mode='%s'>"
+                                        % (self.f.name, self.f.mode))
+        del self.f.name
+        self.assertEquals(repr(self.f), "<_io.FileIO fd=%r mode='%s'>"
+                                        % (self.f.fileno(), self.f.mode))
+        self.f.close()
+        self.assertEquals(repr(self.f), "<_io.FileIO [closed]>")
 
     def testErrors(self):
         f = self.f
@@ -81,7 +88,7 @@
         self.assertRaises(ValueError, f.read, 10) # Open for reading
         f.close()
         self.assert_(f.closed)
-        f = _fileio._FileIO(TESTFN, 'r')
+        f = _FileIO(TESTFN, 'r')
         self.assertRaises(TypeError, f.readinto, "")
         self.assert_(not f.closed)
         f.close()
@@ -107,31 +114,131 @@
         # Windows always returns "[Errno 13]: Permission denied
         # Unix calls dircheck() and returns "[Errno 21]: Is a directory"
         try:
-            _fileio._FileIO('.', 'r')
+            _FileIO('.', 'r')
         except IOError as e:
             self.assertNotEqual(e.errno, 0)
             self.assertEqual(e.filename, ".")
         else:
             self.fail("Should have raised IOError")
 
+    #A set of functions testing that we get expected behaviour if someone has
+    #manually closed the internal file descriptor.  First, a decorator:
+    def ClosedFD(func):
+        @wraps(func)
+        def wrapper(self):
+            #forcibly close the fd before invoking the problem function
+            f = self.f
+            os.close(f.fileno())
+            try:
+                func(self, f)
+            finally:
+                try:
+                    self.f.close()
+                except IOError:
+                    pass
+        return wrapper
+
+    def ClosedFDRaises(func):
+        @wraps(func)
+        def wrapper(self):
+            #forcibly close the fd before invoking the problem function
+            f = self.f
+            os.close(f.fileno())
+            try:
+                func(self, f)
+            except IOError as e:
+                self.assertEqual(e.errno, errno.EBADF)
+            else:
+                self.fail("Should have raised IOError")
+            finally:
+                try:
+                    self.f.close()
+                except IOError:
+                    pass
+        return wrapper
+
+    @ClosedFDRaises
+    def testErrnoOnClose(self, f):
+        f.close()
+
+    @ClosedFDRaises
+    def testErrnoOnClosedWrite(self, f):
+        f.write('a')
+
+    @ClosedFDRaises
+    def testErrnoOnClosedSeek(self, f):
+        f.seek(0)
+
+    @ClosedFDRaises
+    def testErrnoOnClosedTell(self, f):
+        f.tell()
+
+    @ClosedFDRaises
+    def testErrnoOnClosedTruncate(self, f):
+        f.truncate(0)
+
+    @ClosedFD
+    def testErrnoOnClosedSeekable(self, f):
+        f.seekable()
+
+    @ClosedFD
+    def testErrnoOnClosedReadable(self, f):
+        f.readable()
+
+    @ClosedFD
+    def testErrnoOnClosedWritable(self, f):
+        f.writable()
+
+    @ClosedFD
+    def testErrnoOnClosedFileno(self, f):
+        f.fileno()
+
+    @ClosedFD
+    def testErrnoOnClosedIsatty(self, f):
+        self.assertEqual(f.isatty(), False)
+
+    def ReopenForRead(self):
+        try:
+            self.f.close()
+        except IOError:
+            pass
+        self.f = _FileIO(TESTFN, 'r')
+        os.close(self.f.fileno())
+        return self.f
+
+    @ClosedFDRaises
+    def testErrnoOnClosedRead(self, f):
+        f = self.ReopenForRead()
+        f.read(1)
+
+    @ClosedFDRaises
+    def testErrnoOnClosedReadall(self, f):
+        f = self.ReopenForRead()
+        f.readall()
+
+    @ClosedFDRaises
+    def testErrnoOnClosedReadinto(self, f):
+        f = self.ReopenForRead()
+        a = array(b'b', b'x'*10)
+        f.readinto(a)
 
 class OtherFileTests(unittest.TestCase):
 
     def testAbles(self):
         try:
-            f = _fileio._FileIO(TESTFN, "w")
+            f = _FileIO(TESTFN, "w")
             self.assertEquals(f.readable(), False)
             self.assertEquals(f.writable(), True)
             self.assertEquals(f.seekable(), True)
             f.close()
 
-            f = _fileio._FileIO(TESTFN, "r")
+            f = _FileIO(TESTFN, "r")
             self.assertEquals(f.readable(), True)
             self.assertEquals(f.writable(), False)
             self.assertEquals(f.seekable(), True)
             f.close()
 
-            f = _fileio._FileIO(TESTFN, "a+")
+            f = _FileIO(TESTFN, "a+")
             self.assertEquals(f.readable(), True)
             self.assertEquals(f.writable(), True)
             self.assertEquals(f.seekable(), True)
@@ -140,14 +247,14 @@
 
             if sys.platform != "win32":
                 try:
-                    f = _fileio._FileIO("/dev/tty", "a")
+                    f = _FileIO("/dev/tty", "a")
                 except EnvironmentError:
                     # When run in a cron job there just aren't any
                     # ttys, so skip the test.  This also handles other
                     # OS'es that don't support /dev/tty.
                     pass
                 else:
-                    f = _fileio._FileIO("/dev/tty", "a")
+                    f = _FileIO("/dev/tty", "a")
                     self.assertEquals(f.readable(), False)
                     self.assertEquals(f.writable(), True)
                     if sys.platform != "darwin" and \
@@ -164,7 +271,7 @@
         # check invalid mode strings
         for mode in ("", "aU", "wU+", "rw", "rt"):
             try:
-                f = _fileio._FileIO(TESTFN, mode)
+                f = _FileIO(TESTFN, mode)
             except ValueError:
                 pass
             else:
@@ -173,19 +280,35 @@
 
     def testUnicodeOpen(self):
         # verify repr works for unicode too
-        f = _fileio._FileIO(str(TESTFN), "w")
+        f = _FileIO(str(TESTFN), "w")
         f.close()
         os.unlink(TESTFN)
 
+    def testBytesOpen(self):
+        # Opening a bytes filename
+        try:
+            fn = TESTFN.encode("ascii")
+        except UnicodeEncodeError:
+            # Skip test
+            return
+        f = _FileIO(fn, "w")
+        try:
+            f.write(b"abc")
+            f.close()
+            with open(TESTFN, "rb") as f:
+                self.assertEquals(f.read(), b"abc")
+        finally:
+            os.unlink(TESTFN)
+
     def testInvalidFd(self):
-        self.assertRaises(ValueError, _fileio._FileIO, -10)
-        self.assertRaises(OSError, _fileio._FileIO, make_bad_fd())
+        self.assertRaises(ValueError, _FileIO, -10)
+        self.assertRaises(OSError, _FileIO, make_bad_fd())
 
     def testBadModeArgument(self):
         # verify that we get a sensible error message for bad mode argument
         bad_mode = "qwerty"
         try:
-            f = _fileio._FileIO(TESTFN, bad_mode)
+            f = _FileIO(TESTFN, bad_mode)
         except ValueError as msg:
             if msg.args[0] != 0:
                 s = str(msg)
@@ -201,13 +324,13 @@
         def bug801631():
             # SF bug <http://www.python.org/sf/801631>
             # "file.truncate fault on windows"
-            f = _fileio._FileIO(TESTFN, 'w')
-            f.write(bytes(bytearray(range(11))))
+            f = _FileIO(TESTFN, 'w')
+            f.write(bytes(range(11)))
             f.close()
 
-            f = _fileio._FileIO(TESTFN,'r+')
+            f = _FileIO(TESTFN,'r+')
             data = f.read(5)
-            if data != bytes(bytearray(range(5))):
+            if data != bytes(range(5)):
                 self.fail("Read on file opened for update failed %r" % data)
             if f.tell() != 5:
                 self.fail("File pos after read wrong %d" % f.tell())
@@ -245,14 +368,14 @@
                 pass
 
     def testInvalidInit(self):
-        self.assertRaises(TypeError, _fileio._FileIO, "1", 0, 0)
+        self.assertRaises(TypeError, _FileIO, "1", 0, 0)
 
     def testWarnings(self):
         with check_warnings() as w:
             self.assertEqual(w.warnings, [])
-            self.assertRaises(TypeError, _fileio._FileIO, [])
+            self.assertRaises(TypeError, _FileIO, [])
             self.assertEqual(w.warnings, [])
-            self.assertRaises(ValueError, _fileio._FileIO, "/some/invalid/name", "rt")
+            self.assertRaises(ValueError, _FileIO, "/some/invalid/name", "rt")
             self.assertEqual(w.warnings, [])