diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2015-02-21 00:35:53 +0200 |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2015-02-21 00:35:53 +0200 |
commit | 8978b7b87015ab53f0e3bb8d3e7e7b8d3b6e7624 (patch) | |
tree | fb2c027089e31846a421f0a74fb9e4bdbcff99b8 /Lib | |
parent | ec5062617b06692aa8f94f77fe76b60b4c937b9d (diff) | |
parent | e0c33606506b8475e3d396a83d47fc3f1ebce893 (diff) | |
download | cpython-8978b7b87015ab53f0e3bb8d3e7e7b8d3b6e7624.tar.gz |
Issue #5700: io.FileIO() called flush() after closing the file.
flush() was not called in close() if closefd=False.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_io.py | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index c867502e9b..198cc5d32d 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -589,13 +589,43 @@ class IOTest(unittest.TestCase): with self.open(zero, "r") as f: self.assertRaises(OverflowError, f.read) - def test_flush_error_on_close(self): - f = self.open(support.TESTFN, "wb", buffering=0) + def check_flush_error_on_close(self, *args, **kwargs): + # Test that the file is closed despite failed flush + # and that flush() is called before file closed. + f = self.open(*args, **kwargs) + closed = [] def bad_flush(): + closed[:] = [f.closed] raise OSError() f.flush = bad_flush self.assertRaises(OSError, f.close) # exception not swallowed self.assertTrue(f.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + + def test_flush_error_on_close(self): + # raw file + # Issue #5700: io.FileIO calls flush() after file closed + self.check_flush_error_on_close(support.TESTFN, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0) + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', buffering=0, closefd=False) + os.close(fd) + # buffered io + self.check_flush_error_on_close(support.TESTFN, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'wb', closefd=False) + os.close(fd) + # text io + self.check_flush_error_on_close(support.TESTFN, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w') + fd = os.open(support.TESTFN, os.O_WRONLY|os.O_CREAT) + self.check_flush_error_on_close(fd, 'w', closefd=False) + os.close(fd) def test_multi_close(self): f = self.open(support.TESTFN, "wb", buffering=0) @@ -784,13 +814,21 @@ class CommonBufferedTests: self.assertEqual(repr(b), "<%s name=b'dummy'>" % clsname) def test_flush_error_on_close(self): + # Test that buffered file is closed despite failed flush + # and that flush() is called before file closed. raw = self.MockRawIO() + closed = [] def bad_flush(): + closed[:] = [b.closed, raw.closed] raise OSError() raw.flush = bad_flush b = self.tp(raw) self.assertRaises(OSError, b.close) # exception not swallowed self.assertTrue(b.closed) + self.assertTrue(raw.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) def test_close_error_on_close(self): raw = self.MockRawIO() @@ -2679,12 +2717,20 @@ class TextIOWrapperTest(unittest.TestCase): self.assertEqual(content.count("Thread%03d\n" % n), 1) def test_flush_error_on_close(self): + # Test that text file is closed despite failed flush + # and that flush() is called before file closed. txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + closed = [] def bad_flush(): + closed[:] = [txt.closed, txt.buffer.closed] raise OSError() txt.flush = bad_flush self.assertRaises(OSError, txt.close) # exception not swallowed self.assertTrue(txt.closed) + self.assertTrue(txt.buffer.closed) + self.assertTrue(closed) # flush() called + self.assertFalse(closed[0]) # flush() called before file closed + self.assertFalse(closed[1]) def test_close_error_on_close(self): buffer = self.BytesIO(self.testdata) |