/* * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.io.*; /** * @test * @bug 7015589 8054565 * @summary Test that buffering streams are considered closed even when the * close or flush from the underlying stream fails. */ public class FailingFlushAndClose { static int failed; static void fail(String msg) { System.err.println("FAIL: " + msg); failed++; } static void failWithIOE(String msg) throws IOException { fail(msg); throw new IOException(msg); } static class FailingCloseInputStream extends InputStream { boolean closed; @Override public int read()throws IOException { if (closed) failWithIOE("input stream is closed"); return 1; } @Override public void close() throws IOException { if (!closed) { closed = true; throw new IOException("close failed"); } } } static class FailingCloseOutputStream extends OutputStream { boolean closed; @Override public void write(int b) throws IOException { if (closed) failWithIOE("output stream is closed"); } @Override public void flush() throws IOException { if (closed) failWithIOE("output stream is closed"); } @Override public void close() throws IOException { if (!closed) { closed = true; throw new IOException("close failed"); } } } static class FailingFlushOutputStream extends OutputStream { boolean closed; @Override public void write(int b) throws IOException { if (closed) failWithIOE("output stream is closed"); } @Override public void flush() throws IOException { if (closed) { failWithIOE("output stream is closed"); } else { throw new IOException("flush failed"); } } @Override public void close() throws IOException { closed = true; } } static class FailingCloseReader extends Reader { boolean closed; @Override public int read(char[] cbuf, int off, int len) throws IOException { if (closed) failWithIOE("reader is closed"); return 1; } @Override public void close() throws IOException { if (!closed) { closed = true; throw new IOException("close failed"); } } } static class FailingCloseWriter extends Writer { boolean closed; @Override public void write(char[] cbuf, int off, int len) throws IOException { if (closed) failWithIOE("writer is closed"); } @Override public void flush() throws IOException { if (closed) failWithIOE("writer is closed"); } @Override public void close() throws IOException { if (!closed) { closed = true; throw new IOException("close failed"); } } } static class FailingFlushWriter extends Writer { boolean closed; @Override public void write(char[] cbuf, int off, int len) throws IOException { if (closed) failWithIOE("writer is closed"); } @Override public void flush() throws IOException { if (closed) { failWithIOE("writer is closed"); } else { throw new IOException("flush failed"); } } @Override public void close() throws IOException { if (!closed) { closed = true; throw new IOException("close failed"); } } } static InputStream testFailingClose(InputStream in) throws IOException { System.out.println(in.getClass()); in.read(new byte[100]); try { in.close(); fail("close did not fail"); } catch (IOException expected) { } try { in.read(new byte[100]); fail("read did not fail"); } catch (IOException expected) { } return in; } static OutputStream testFailingClose(OutputStream out) throws IOException { System.out.println(out.getClass()); out.write(1); try { out.close(); fail("close did not fail"); } catch (IOException expected) { } try { out.write(1); if (!(out instanceof BufferedOutputStream)) fail("write did not fail"); } catch (IOException expected) { } return out; } static OutputStream testFailingFlush(OutputStream out) throws IOException { System.out.println(out.getClass()); out.write(1); try { out.flush(); fail("flush did not fail"); } catch (IOException expected) { } if (out instanceof BufferedOutputStream) { out.write(1); try { out.close(); fail("close did not fail"); } catch (IOException expected) { } } return out; } static void closeAgain(InputStream in) throws IOException { // assert the given stream should already be closed. try { in.close(); } catch (IOException expected) { fail("unexpected IOException from subsequent close"); } } static void closeAgain(OutputStream out) throws IOException { // assert the given stream should already be closed. try { out.close(); } catch (IOException expected) { fail("unexpected IOException from subsequent close"); } } static Reader testFailingClose(Reader r) throws IOException { System.out.println(r.getClass()); r.read(new char[100]); try { r.close(); fail("close did not fail"); } catch (IOException expected) { } try { r.read(new char[100]); fail("read did not fail"); } catch (IOException expected) { } return r; } static Writer testFailingClose(Writer w) throws IOException { System.out.println(w.getClass()); w.write("message"); try { w.close(); fail("close did not fail"); } catch (IOException expected) { } try { w.write("another message"); fail("write did not fail"); } catch (IOException expected) { } return w; } static Writer testFailingFlush(Writer w) throws IOException { System.out.println(w.getClass()); w.write("message"); try { w.flush(); fail("flush did not fail"); } catch (IOException expected) { } if (w instanceof BufferedWriter) { // assume this message will be buffered w.write("another message"); try { w.close(); fail("close did not fail"); } catch (IOException expected) { } } return w; } static Reader closeAgain(Reader r) throws IOException { // assert the given stream should already be closed. try { r.close(); } catch (IOException expected) { fail("unexpected IOException from subsequent close"); } return r; } static Writer closeAgain(Writer w) throws IOException { // assert the given stream should already be closed. try { w.close(); } catch (IOException expected) { fail("unexpected IOException from subsequent close"); } return w; } public static void main(String[] args) throws IOException { closeAgain(testFailingClose(new BufferedInputStream(new FailingCloseInputStream()))); closeAgain(testFailingClose(new BufferedOutputStream(new FailingCloseOutputStream()))); closeAgain(testFailingClose(new BufferedReader(new FailingCloseReader()))); closeAgain(testFailingClose(new BufferedWriter(new FailingCloseWriter()))); closeAgain(testFailingFlush(new BufferedOutputStream(new FailingFlushOutputStream()))); closeAgain(testFailingFlush(new BufferedWriter(new FailingFlushWriter()))); if (failed > 0) throw new RuntimeException(failed + " test(s) failed - see log for details"); } }