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
     76     public String toString() {
     77         return getClass().getName();
     78     }
     79 
     80     private class WrapperSinkTester extends CharSinkTester {
     81         private ClosableStringWriter delegate;
     82 
     83         @Override
     84         public Writer create() throws Exception {
     85             delegate = new ClosableStringWriter();
     86             return CharWrapperTester.this.create(delegate);
     87         }
     88 
     89         @Override
     90         public char[] getChars() throws Exception {
     91             return decode(delegate.buffer.toString().toCharArray());
     92         }
     93 
     94         @Override
     95         public String toString() {
     96             return CharWrapperTester.this.toString();
     97         }
     98     }
     99 
    100     public class WrapperTestCase extends TestCase {
    101 
    102         private WrapperTestCase(String name) {
    103             super(name);
    104         }
    105 
    106         @Override
    107         public String getName() {
    108             return CharWrapperTester.this.toString() + ":" + super.getName();
    109         }
    110 
    111         public void wrapperTestFlushThrowsViaFlushSuppressed() throws Exception {
    112             FailOnFlushWriter delegate = new FailOnFlushWriter();
    113             Writer o = create(delegate);
    114             o.write("BUT");
    115             o.write("TERS");
    116             o.flush();
    117             assertTrue(delegate.flushed);
    118         }
    119 
    120         public void wrapperTestFlushThrowsViaCloseSuppressed() throws Exception {
    121             FailOnFlushWriter delegate = new FailOnFlushWriter();
    122             Writer o = create(delegate);
    123             o.write("BUT");
    124             o.write("TERS");
    125             o.close();
    126             assertTrue(delegate.flushed);
    127         }
    128 
    129         public void wrapperTestFlushThrowsViaFlush() throws Exception {
    130             FailOnFlushWriter delegate = new FailOnFlushWriter();
    131 
    132             Writer o = create(delegate);
    133             try {
    134                 // any of these is permitted to flush
    135                 o.write("BUT");
    136                 o.write("TERS");
    137                 o.flush();
    138                 assertTrue(delegate.flushed);
    139                 fail("flush exception ignored");
    140             } catch (IOException expected) {
    141                 assertEquals("Flush failed", expected.getMessage());
    142             }
    143         }
    144 
    145         public void wrapperTestFlushThrowsViaClose() throws Exception {
    146             FailOnFlushWriter delegate = new FailOnFlushWriter();
    147 
    148             Writer o = create(delegate);
    149             try {
    150                 // any of these is permitted to flush
    151                 o.write("BUT");
    152                 o.write("TERS");
    153                 o.close();
    154                 assertTrue(delegate.flushed);
    155                 fail("flush exception ignored");
    156             } catch (IOException expected) {
    157                 assertEquals("Flush failed", expected.getMessage());
    158             }
    159 
    160             try {
    161                 o.write("BARK");
    162                 fail("expected already closed exception");
    163             } catch (IOException expected) {
    164             }
    165         }
    166 
    167         public void wrapperTestCloseThrows() throws Exception {
    168             FailOnCloseWriter delegate = new FailOnCloseWriter();
    169             Writer o = create(delegate);
    170             try {
    171                 o.close();
    172                 assertTrue(delegate.closed);
    173                 fail("close exception ignored");
    174             } catch (IOException expected) {
    175                 assertEquals("Close failed", expected.getMessage());
    176             }
    177         }
    178 
    179         public void wrapperTestCloseThrowsSuppressed() throws Exception {
    180             FailOnCloseWriter delegate = new FailOnCloseWriter();
    181             Writer o = create(delegate);
    182             o.close();
    183             assertTrue(delegate.closed);
    184         }
    185 
    186         // adding a new test? Don't forget to update createTests().
    187     }
    188 
    189     /**
    190      * A custom Writer that respects the closed state. The built-in StringWriter
    191      * doesn't respect close(), which makes testing wrapped streams difficult.
    192      */
    193     private static class ClosableStringWriter extends Writer {
    194         private final StringBuilder buffer = new StringBuilder();
    195         private boolean closed = false;
    196 
    197         @Override
    198         public void close() throws IOException {
    199             closed = true;
    200         }
    201 
    202         @Override
    203         public void flush() throws IOException {
    204         }
    205 
    206         @Override
    207         public void write(char[] buf, int offset, int count) throws IOException {
    208             if (closed) {
    209                 throw new IOException();
    210             }
    211             buffer.append(buf, offset, count);
    212         }
    213     }
    214 
    215     private static class FailOnFlushWriter extends Writer {
    216         boolean flushed = false;
    217         boolean closed = false;
    218 
    219         @Override
    220         public void write(char[] buf, int offset, int count) throws IOException {
    221             if (closed) {
    222                 throw new IOException("Already closed");
    223             }
    224         }
    225 
    226         @Override
    227         public void close() throws IOException {
    228             closed = true;
    229             flush();
    230         }
    231 
    232         @Override
    233         public void flush() throws IOException {
    234             if (!flushed) {
    235                 flushed = true;
    236                 throw new IOException("Flush failed");
    237             }
    238         }
    239     }
    240 
    241     private static class FailOnCloseWriter extends Writer {
    242         boolean closed = false;
    243 
    244         @Override
    245         public void flush() throws IOException {
    246         }
    247 
    248         @Override
    249         public void write(char[] buf, int offset, int count) throws IOException {
    250         }
    251 
    252         @Override
    253         public void close() throws IOException {
    254             closed = true;
    255             throw new IOException("Close failed");
    256         }
    257     }
    258 }