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.IOException;
     24 import java.io.Writer;
     25 
     26 /**
     27  * Tests behaviour common to wrapping and filtering implementations of {@link
     28  * Writer}.
     29  */
     30 public abstract class CharWrapperTester {
     31 
     32     private boolean throwsExceptions = true;
     33 
     34     /**
     35      * Creates a new output stream that receives one stream of chars, optionally
     36      * transforms it, and emits another stream of chars to {@code delegate}.
     37      */
     38     public abstract Writer create(Writer delegate) throws Exception;
     39 
     40     /**
     41      * Decodes the chars received by the delegate into their original form: the
     42      * chars originally received by this wrapper.
     43      */
     44     public abstract char[] decode(char[] delegateChars) throws Exception;
     45 
     46     /**
     47      * Configures whether the writer is expected to throw exceptions when an
     48      * error is encountered. Classes like {@code PrintWriter} report errors via
     49      * an API method instead.
     50      */
     51     public CharWrapperTester setThrowsExceptions(boolean throwsExceptions) {
     52         this.throwsExceptions = throwsExceptions;
     53         return this;
     54     }
     55 
     56     public final TestSuite createTests() {
     57         TestSuite result = new TestSuite();
     58         result.addTest(new WrapperSinkTester()
     59                 .setThrowsExceptions(throwsExceptions)
     60                 .createTests());
     61 
     62         if (throwsExceptions) {
     63             result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaFlush"));
     64             result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaClose"));
     65             result.addTest(new WrapperTestCase("wrapperTestCloseThrows"));
     66         } else {
     67             result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaFlushSuppressed"));
     68             result.addTest(new WrapperTestCase("wrapperTestFlushThrowsViaCloseSuppressed"));
     69             result.addTest(new WrapperTestCase("wrapperTestCloseThrowsSuppressed"));
     70         }
     71 
     72         return result;
     73     }
     74 
     75     @Override public String toString() {
     76         return getClass().getName();
     77     }
     78 
     79     private class WrapperSinkTester extends CharSinkTester {
     80         private ClosableStringWriter delegate;
     81 
     82         @Override public Writer create() throws Exception {
     83             delegate = new ClosableStringWriter();
     84             return CharWrapperTester.this.create(delegate);
     85         }
     86 
     87         @Override public char[] getChars() throws Exception {
     88             return decode(delegate.buffer.toString().toCharArray());
     89         }
     90 
     91         @Override public String toString() {
     92             return CharWrapperTester.this.toString();
     93         }
     94     }
     95 
     96     public class WrapperTestCase extends TestCase {
     97 
     98         private WrapperTestCase(String name) {
     99             super(name);
    100         }
    101 
    102         @Override public String getName() {
    103             return CharWrapperTester.this.toString() + ":" + super.getName();
    104         }
    105 
    106         public void wrapperTestFlushThrowsViaFlushSuppressed() throws Exception {
    107             FailOnFlushWriter delegate = new FailOnFlushWriter();
    108             Writer o = create(delegate);
    109             o.write("BUT");
    110             o.write("TERS");
    111             o.flush();
    112             assertTrue(delegate.flushed);
    113         }
    114 
    115         public void wrapperTestFlushThrowsViaCloseSuppressed() throws Exception {
    116             FailOnFlushWriter delegate = new FailOnFlushWriter();
    117             Writer o = create(delegate);
    118             o.write("BUT");
    119             o.write("TERS");
    120             o.close();
    121             assertTrue(delegate.flushed);
    122         }
    123 
    124         public void wrapperTestFlushThrowsViaFlush() throws Exception {
    125             FailOnFlushWriter delegate = new FailOnFlushWriter();
    126 
    127             Writer o = create(delegate);
    128             try {
    129                 // any of these is permitted to flush
    130                 o.write("BUT");
    131                 o.write("TERS");
    132                 o.flush();
    133                 assertTrue(delegate.flushed);
    134                 fail("flush exception ignored");
    135             } catch (IOException expected) {
    136                 assertEquals("Flush failed" , expected.getMessage());
    137             }
    138         }
    139 
    140         public void wrapperTestFlushThrowsViaClose() throws Exception {
    141             FailOnFlushWriter delegate = new FailOnFlushWriter();
    142 
    143             Writer o = create(delegate);
    144             try {
    145                 // any of these is permitted to flush
    146                 o.write("BUT");
    147                 o.write("TERS");
    148                 o.close();
    149                 assertTrue(delegate.flushed);
    150                 fail("flush exception ignored");
    151             } catch (IOException expected) {
    152                 assertEquals("Flush failed" , expected.getMessage());
    153             }
    154 
    155             try {
    156                 o.write("BARK");
    157                 fail("expected already closed exception");
    158             } catch (IOException expected) {
    159             }
    160         }
    161 
    162         public void wrapperTestCloseThrows() throws Exception {
    163             FailOnCloseWriter delegate = new FailOnCloseWriter();
    164             Writer o = create(delegate);
    165             try {
    166                 o.close();
    167                 assertTrue(delegate.closed);
    168                 fail("close exception ignored");
    169             } catch (IOException expected) {
    170                 assertEquals("Close failed" , expected.getMessage());
    171             }
    172         }
    173 
    174         public void wrapperTestCloseThrowsSuppressed() throws Exception {
    175             FailOnCloseWriter delegate = new FailOnCloseWriter();
    176             Writer o = create(delegate);
    177             o.close();
    178             assertTrue(delegate.closed);
    179         }
    180 
    181         // adding a new test? Don't forget to update createTests().
    182     }
    183 
    184     /**
    185      * A custom Writer that respects the closed state. The built-in StringWriter
    186      * doesn't respect close(), which makes testing wrapped streams difficult.
    187      */
    188     private static class ClosableStringWriter extends Writer {
    189         private final StringBuilder buffer = new StringBuilder();
    190         private boolean closed = false;
    191 
    192         @Override public void close() throws IOException {
    193             closed = true;
    194         }
    195 
    196         @Override public void flush() throws IOException {}
    197 
    198         @Override public void write(char[] buf, int offset, int count) throws IOException {
    199             if (closed) {
    200                 throw new IOException();
    201             }
    202             buffer.append(buf, offset, count);
    203         }
    204     }
    205 
    206     private static class FailOnFlushWriter extends Writer {
    207         boolean flushed = false;
    208         boolean closed = false;
    209 
    210         @Override public void write(char[] buf, int offset, int count) throws IOException {
    211             if (closed) {
    212                 throw new IOException("Already closed");
    213             }
    214         }
    215 
    216         @Override public void close() throws IOException {
    217             closed = true;
    218             flush();
    219         }
    220 
    221         @Override public void flush() throws IOException {
    222             if (!flushed) {
    223                 flushed = true;
    224                 throw new IOException("Flush failed");
    225             }
    226         }
    227     }
    228 
    229     private static class FailOnCloseWriter extends Writer {
    230         boolean closed = false;
    231 
    232         @Override public void flush() throws IOException {}
    233 
    234         @Override public void write(char[] buf, int offset, int count) throws IOException {}
    235 
    236         @Override public void close() throws IOException {
    237             closed = true;
    238             throw new IOException("Close failed");
    239         }
    240     }
    241 }