1e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes/*
2e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  Licensed to the Apache Software Foundation (ASF) under one or more
3e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  contributor license agreements.  See the NOTICE file distributed with
4e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  this work for additional information regarding copyright ownership.
5e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  The ASF licenses this file to You under the Apache License, Version 2.0
6e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  (the "License"); you may not use this file except in compliance with
7e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  the License.  You may obtain a copy of the License at
8e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *
9e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *     http://www.apache.org/licenses/LICENSE-2.0
10e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *
11e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  Unless required by applicable law or agreed to in writing, software
12e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  distributed under the License is distributed on an "AS IS" BASIS,
13e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  See the License for the specific language governing permissions and
15e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes *  limitations under the License.
16e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes */
17e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
18e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughespackage org.apache.harmony.testframework;
19e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
20e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughesimport junit.framework.TestCase;
21e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughesimport junit.framework.TestSuite;
22e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
23e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughesimport java.io.ByteArrayOutputStream;
24e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughesimport java.io.IOException;
25e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughesimport java.io.OutputStream;
26e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
27e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes/**
28e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes * Tests behaviour common to wrapping and filtering implementations of {@link
29e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes * OutputStream}.
30e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes */
31e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughespublic abstract class WrapperTester {
32e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
33e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    private boolean throwsExceptions = true;
34e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
35e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    /**
36e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     * Creates a new output stream that receives one stream of bytes, optionally
37e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     * transforms it, and emits another stream of bytes to {@code delegate}.
38e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     */
39e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    public abstract OutputStream create(OutputStream delegate) throws Exception;
40e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
41e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    /**
42e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     * Decodes the bytes received by the delegate into their original form: the
43e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     * bytes originally received by this wrapper.
44e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     */
45e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    public abstract byte[] decode(byte[] delegateBytes) throws Exception;
46e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
47e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    /**
48e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     * Configures whether the stream is expected to throw exceptions when an
49e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     * error is encountered. Classes like {@code PrintStream} report errors via
50e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     * an API method instead.
51e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes     */
52e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    public WrapperTester setThrowsExceptions(boolean throwsExceptions) {
53e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        this.throwsExceptions = throwsExceptions;
54e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        return this;
55e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    }
56e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
57e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    public final TestSuite createTests() {
58e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        TestSuite result = new TestSuite();
59e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        result.addTest(new WrapperSinkTester()
60e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                .setThrowsExceptions(throwsExceptions)
61e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                .createTests());
62e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
63e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        if (throwsExceptions) {
64e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaFlush"));
65e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaClose"));
66e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            result.addTest(new WrapperTestCase("wrapperTestCloseThrows"));
67e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        } else {
68e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaFlushSuppressed"));
69e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaCloseSuppressed"));
70e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            result.addTest(new WrapperTestCase("wrapperTestCloseThrowsSuppressed"));
71e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
72e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
73e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        return result;
74e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    }
75e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
76e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    @Override public String toString() {
77e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        return getClass().getName();
78e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    }
79e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
80e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    private class WrapperSinkTester extends SinkTester {
81e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        private ClosableByteArrayOutputStream delegate;
82e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
83e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public OutputStream create() throws Exception {
84e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            delegate = new ClosableByteArrayOutputStream();
85e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            return WrapperTester.this.create(delegate);
86e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
87e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
88e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public byte[] getBytes() throws Exception {
89e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            return WrapperTester.this.decode(delegate.bytesOut.toByteArray());
90e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
91e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
92e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public String toString() {
93e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            return WrapperTester.this.toString();
94e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
95e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    }
96e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
97e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    public class WrapperTestCase extends TestCase {
98e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
99e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        private WrapperTestCase(String name) {
100e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            super(name);
101e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
102e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
103e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public String getName() {
104e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            return WrapperTester.this.toString() + ":" + super.getName();
105e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
106e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
107e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        public void wrapperTestFlushThrowsViaFlushSuppressed() throws Exception {
108e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
109e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            OutputStream o = create(delegate);
110e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            o.write(new byte[] { 8, 6, 7, 5 });
111e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            o.write(new byte[] { 3, 0, 9 });
112e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            o.flush();
113e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            assertTrue(delegate.flushed);
114e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
115e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
116e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        public void wrapperTestFlushThrowsViaCloseSuppressed() throws Exception {
117e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
118e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            OutputStream o = create(delegate);
119e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            o.write(new byte[] { 8, 6, 7, 5 });
120e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            o.write(new byte[] { 3, 0, 9 });
121e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            o.close();
122e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            assertTrue(delegate.flushed);
123e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
124e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
125e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        public void wrapperTestFlushThrowsViaFlush() throws Exception {
126e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
127e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
128e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            OutputStream o = create(delegate);
129e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            try {
130e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                // any of these is permitted to flush
131e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                o.write(new byte[] { 8, 6, 7, 5 });
132e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                o.write(new byte[] { 3, 0, 9 });
133e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                o.flush();
134e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                assertTrue(delegate.flushed);
135e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                fail("flush exception ignored");
136e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            } catch (IOException expected) {
137e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                assertEquals("Flush failed" , expected.getMessage());
138e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            }
139e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
140e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
141e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        public void wrapperTestFlushThrowsViaClose() throws Exception {
142e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
143e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
144e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            OutputStream o = create(delegate);
145e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            try {
146e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                // any of these is permitted to flush
147e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                o.write(new byte[] { 8, 6, 7, 5 });
148e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                o.write(new byte[] { 3, 0, 9 });
149e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                o.close();
150e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                assertTrue(delegate.flushed);
151e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                fail("flush exception ignored");
152e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            } catch (IOException expected) {
153e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                assertEquals("Flush failed" , expected.getMessage());
154e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            }
155e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
156e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            try {
157e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                o.write(new byte[] { 4, 4, 5 });
158e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                fail("expected already closed exception");
159e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            } catch (IOException expected) {
160e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            }
161e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
162e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
163e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        public void wrapperTestCloseThrows() throws Exception {
164e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            FailOnCloseOutputStream delegate = new FailOnCloseOutputStream();
165e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            OutputStream o = create(delegate);
166e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            try {
167e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                o.close();
168e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                assertTrue(delegate.closed);
169e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                fail("close exception ignored");
170e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            } catch (IOException expected) {
171e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                assertEquals("Close failed" , expected.getMessage());
172e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            }
173e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
174e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
175e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        public void wrapperTestCloseThrowsSuppressed() throws Exception {
176e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            FailOnCloseOutputStream delegate = new FailOnCloseOutputStream();
177e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            OutputStream o = create(delegate);
178e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            o.close();
179e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            assertTrue(delegate.closed);
180e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
181e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
182e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        // adding a new test? Don't forget to update createTests().
183e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    }
184e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
185e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    private static class ClosableByteArrayOutputStream extends OutputStream {
186e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        private final ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
187e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        private boolean closed = false;
188e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
189e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public void close() throws IOException {
190e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            closed = true;
191e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
192e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
193e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public void write(int oneByte) throws IOException {
194e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            if (closed) {
195e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                throw new IOException();
196e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            }
197e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            bytesOut.write(oneByte);
198e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
199e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    }
200e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
201e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    private static class FailOnFlushOutputStream extends OutputStream {
202e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        boolean flushed = false;
203e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        boolean closed = false;
204e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
205e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public void write(int oneByte) throws IOException {
206e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            if (closed) {
207e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                throw new IOException("Already closed");
208e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            }
209e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
210e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
211e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public void close() throws IOException {
212e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            closed = true;
213e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            flush();
214e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
215e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
216e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public void flush() throws IOException {
217e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            if (!flushed) {
218e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                flushed = true;
219e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes                throw new IOException("Flush failed");
220e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            }
221e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
222e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    }
223e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
224e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    private static class FailOnCloseOutputStream extends ByteArrayOutputStream {
225e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        boolean closed = false;
226e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes
227e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        @Override public void close() throws IOException {
228e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            closed = true;
229e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes            throw new IOException("Close failed");
230e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes        }
231e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes    }
232e98fbf8686c5289bf03fe5c3de7ff82d3a77104dElliott Hughes}
233