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