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 18package org.apache.harmony.testframework; 19 20import junit.framework.Assert; 21import junit.framework.TestCase; 22import junit.framework.TestSuite; 23 24import java.io.IOException; 25import java.io.Writer; 26import java.util.Arrays; 27import java.util.Random; 28 29/** 30 * Tests behaviour common to all implementations of {@link Writer}. This adapts 31 * writers that collects untransformed chars so that they may be tested. 32 */ 33public abstract class CharSinkTester { 34 35 private boolean throwsExceptions = true; 36 37 /** 38 * Creates a new writer ready to receive an arbitrary number of chars. Each 39 * time this method is invoked, any previously returned writers may be 40 * discarded. 41 */ 42 public abstract Writer create() throws Exception; 43 44 /** 45 * Returns the current set of chars written to the writer last returned by 46 * {@link #create}, and releases any resources held by that writer. 47 */ 48 public abstract char[] getChars() throws Exception; 49 50 /** 51 * Configures whether the writer is expected to throw exceptions when an 52 * error is encountered. Classes like {@code PrintWriter} report errors via 53 * an API method instead. 54 */ 55 public CharSinkTester setThrowsExceptions(boolean throwsExceptions) { 56 this.throwsExceptions = throwsExceptions; 57 return this; 58 } 59 60 public final TestSuite createTests() { 61 TestSuite result = new TestSuite(); 62 result.addTest(new SinkTestCase("sinkTestNoWriting")); 63 result.addTest(new SinkTestCase("sinkTestWriteZeroChars")); 64 result.addTest(new SinkTestCase("sinkTestWriteCharByChar")); 65 result.addTest(new SinkTestCase("sinkTestWriteArray")); 66 result.addTest(new SinkTestCase("sinkTestWriteOffset")); 67 result.addTest(new SinkTestCase("sinkTestWriteLargeArray")); 68 69 if (throwsExceptions) { 70 result.addTest(new SinkTestCase("sinkTestWriteAfterClose")); 71 } else { 72 result.addTest(new SinkTestCase("sinkTestWriteAfterCloseSuppressed")); 73 } 74 75 return result; 76 } 77 78 @Override public String toString() { 79 return getClass().getName(); 80 } 81 82 private static void assertArrayEquals(char[] expected, char[] actual) { 83 Assert.assertEquals(Arrays.toString(expected), Arrays.toString(actual)); 84 } 85 86 public class SinkTestCase extends TestCase { 87 88 private SinkTestCase(String name) { 89 super(name); 90 } 91 92 public void sinkTestNoWriting() throws Exception { 93 char[] expected = new char[] {}; 94 95 Writer out = create(); 96 out.close(); 97 assertArrayEquals(expected, getChars()); 98 } 99 100 public void sinkTestWriteZeroChars() throws Exception { 101 char[] expected = new char[] {}; 102 103 Writer out = create(); 104 char[] a = new char[1024]; 105 out.write(a, 1000, 0); 106 out.write(a, 0, 0); 107 out.write(new char[] {}); 108 109 out.close(); 110 assertArrayEquals(expected, getChars()); 111 } 112 113 public void sinkTestWriteCharByChar() throws Exception { 114 char[] expected = "EFGCDECBA".toCharArray(); 115 116 Writer out = create(); 117 for (char c : expected) { 118 out.write(c); 119 } 120 121 out.close(); 122 assertArrayEquals(expected, getChars()); 123 } 124 125 public void sinkTestWriteArray() throws Exception { 126 char[] expected = "EFGCDECBA".toCharArray(); 127 128 Writer out = create(); 129 130 out.write("EF".toCharArray()); 131 out.write("GCDE".toCharArray()); 132 out.write("CBA".toCharArray()); 133 134 out.close(); 135 assertArrayEquals(expected, getChars()); 136 } 137 138 public void sinkTestWriteOffset() throws Exception { 139 char[] expected = "EFGCDECBA".toCharArray(); 140 Writer out = create(); 141 142 char[] a = new char[1024]; 143 a[1000] = 'E'; 144 a[1001] = 'F'; 145 out.write(a, 1000, 2); 146 147 char[] b = new char[1024]; 148 b[1020] = 'G'; 149 b[1021] = 'C'; 150 b[1022] = 'D'; 151 b[1023] = 'E'; 152 out.write(b, 1020, 4); 153 154 char[] c = new char[1024]; 155 c[0] = 'C'; 156 c[1] = 'B'; 157 c[2] = 'A'; 158 out.write(c, 0, 3); 159 160 out.close(); 161 assertArrayEquals(expected, getChars()); 162 } 163 164 public void sinkTestWriteLargeArray() throws Exception { 165 Random dice = new Random(); 166 char[] expected = new char[(1024 * 1024) + 1]; // 2 MB + 1 char 167 for (int c = 0; c < expected.length; c++) { 168 expected[c] = (char) ('A' + dice.nextInt(26)); 169 } 170 171 Writer out = create(); 172 out.write(expected); 173 out.close(); 174 175 assertArrayEquals(expected, getChars()); 176 } 177 178 public void sinkTestWriteAfterClose() throws Exception { 179 char[] expectedChars = "EF".toCharArray(); 180 Writer out = create(); 181 182 out.write(expectedChars); 183 out.close(); 184 185 try { 186 out.write("GCDE".toCharArray()); 187 fail("expected already closed exception"); 188 } catch (IOException expected) { 189 } 190 191 assertArrayEquals(expectedChars, getChars()); 192 } 193 194 public void sinkTestWriteAfterCloseSuppressed() throws Exception { 195 Writer out = create(); 196 out.write("EF".toCharArray()); 197 out.close(); 198 out.write("GCDE".toCharArray()); // no exception expected! 199 } 200 201 // adding a new test? Don't forget to update createTests(). 202 203 @Override public String getName() { 204 return CharSinkTester.this.toString() + ":" + super.getName(); 205 } 206 } 207} 208