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
     77     public String toString() {
     78         return getClass().getName();
     79     }
     80 
     81     private class WrapperSinkTester extends SinkTester {
     82         private ClosableByteArrayOutputStream delegate;
     83 
     84         @Override
     85         public OutputStream create() throws Exception {
     86             delegate = new ClosableByteArrayOutputStream();
     87             return WrapperTester.this.create(delegate);
     88         }
     89 
     90         @Override
     91         public byte[] getBytes() throws Exception {
     92             return WrapperTester.this.decode(delegate.bytesOut.toByteArray());
     93         }
     94 
     95         @Override
     96         public String toString() {
     97             return WrapperTester.this.toString();
     98         }
     99     }
    100 
    101     public class WrapperTestCase extends TestCase {
    102 
    103         private WrapperTestCase(String name) {
    104             super(name);
    105         }
    106 
    107         @Override
    108         public String getName() {
    109             return WrapperTester.this.toString() + ":" + super.getName();
    110         }
    111 
    112         public void wrapperTestFlushThrowsViaFlushSuppressed() throws Exception {
    113             FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
    114             OutputStream o = create(delegate);
    115             o.write(new byte[] { 8, 6, 7, 5 });
    116             o.write(new byte[] { 3, 0, 9 });
    117             o.flush();
    118             assertTrue(delegate.flushed);
    119         }
    120 
    121         public void wrapperTestFlushThrowsViaCloseSuppressed() throws Exception {
    122             FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
    123             OutputStream o = create(delegate);
    124             o.write(new byte[] { 8, 6, 7, 5 });
    125             o.write(new byte[] { 3, 0, 9 });
    126             o.close();
    127             assertTrue(delegate.flushed);
    128         }
    129 
    130         public void wrapperTestFlushThrowsViaFlush() throws Exception {
    131             FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
    132 
    133             OutputStream o = create(delegate);
    134             try {
    135                 // any of these is permitted to flush
    136                 o.write(new byte[] { 8, 6, 7, 5 });
    137                 o.write(new byte[] { 3, 0, 9 });
    138                 o.flush();
    139                 assertTrue(delegate.flushed);
    140                 fail("flush exception ignored");
    141             } catch (IOException expected) {
    142                 assertEquals("Flush failed", expected.getMessage());
    143             }
    144         }
    145 
    146         public void wrapperTestFlushThrowsViaClose() throws Exception {
    147             FailOnFlushOutputStream delegate = new FailOnFlushOutputStream();
    148 
    149             OutputStream o = create(delegate);
    150             try {
    151                 // any of these is permitted to flush
    152                 o.write(new byte[] { 8, 6, 7, 5 });
    153                 o.write(new byte[] { 3, 0, 9 });
    154                 o.close();
    155                 assertTrue(delegate.flushed);
    156                 fail("flush exception ignored");
    157             } catch (IOException expected) {
    158                 assertEquals("Flush failed", expected.getMessage());
    159             }
    160 
    161             try {
    162                 o.write(new byte[] { 4, 4, 5 });
    163                 fail("expected already closed exception");
    164             } catch (IOException expected) {
    165             }
    166         }
    167 
    168         public void wrapperTestCloseThrows() throws Exception {
    169             FailOnCloseOutputStream delegate = new FailOnCloseOutputStream();
    170             OutputStream o = create(delegate);
    171             try {
    172                 o.close();
    173                 assertTrue(delegate.closed);
    174                 fail("close exception ignored");
    175             } catch (IOException expected) {
    176                 assertEquals("Close failed", expected.getMessage());
    177             }
    178         }
    179 
    180         public void wrapperTestCloseThrowsSuppressed() throws Exception {
    181             FailOnCloseOutputStream delegate = new FailOnCloseOutputStream();
    182             OutputStream o = create(delegate);
    183             o.close();
    184             assertTrue(delegate.closed);
    185         }
    186 
    187         // adding a new test? Don't forget to update createTests().
    188     }
    189 
    190     private static class ClosableByteArrayOutputStream extends OutputStream {
    191         private final ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
    192         private boolean closed = false;
    193 
    194         @Override
    195         public void close() throws IOException {
    196             closed = true;
    197         }
    198 
    199         @Override
    200         public void write(int oneByte) throws IOException {
    201             if (closed) {
    202                 throw new IOException();
    203             }
    204             bytesOut.write(oneByte);
    205         }
    206     }
    207 
    208     private static class FailOnFlushOutputStream extends OutputStream {
    209         boolean flushed = false;
    210         boolean closed = false;
    211 
    212         @Override
    213         public void write(int oneByte) throws IOException {
    214             if (closed) {
    215                 throw new IOException("Already closed");
    216             }
    217         }
    218 
    219         @Override
    220         public void close() throws IOException {
    221             closed = true;
    222             flush();
    223         }
    224 
    225         @Override
    226         public void flush() throws IOException {
    227             if (!flushed) {
    228                 flushed = true;
    229                 throw new IOException("Flush failed");
    230             }
    231         }
    232     }
    233 
    234     private static class FailOnCloseOutputStream extends ByteArrayOutputStream {
    235         boolean closed = false;
    236 
    237         @Override
    238         public void close() throws IOException {
    239             closed = true;
    240             throw new IOException("Close failed");
    241         }
    242     }
    243 }
    244