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