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.Assert;
21 import junit.framework.TestCase;
22 import junit.framework.TestSuite;
23 
24 import java.io.IOException;
25 import java.io.Writer;
26 import java.util.Arrays;
27 import 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  */
33 public 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      */
create()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      */
getChars()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      */
setThrowsExceptions(boolean throwsExceptions)55     public CharSinkTester setThrowsExceptions(boolean throwsExceptions) {
56         this.throwsExceptions = throwsExceptions;
57         return this;
58     }
59 
createTests()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
toString()79     public String toString() {
80         return getClass().getName();
81     }
82 
assertArrayEquals(char[] expected, char[] actual)83     private static void assertArrayEquals(char[] expected, char[] actual) {
84         Assert.assertEquals(Arrays.toString(expected), Arrays.toString(actual));
85     }
86 
87     public class SinkTestCase extends TestCase {
88 
SinkTestCase(String name)89         private SinkTestCase(String name) {
90             super(name);
91         }
92 
sinkTestNoWriting()93         public void sinkTestNoWriting() throws Exception {
94             char[] expected = new char[] { };
95 
96             Writer out = create();
97             out.close();
98             assertArrayEquals(expected, getChars());
99         }
100 
sinkTestWriteZeroChars()101         public void sinkTestWriteZeroChars() throws Exception {
102             char[] expected = new char[] { };
103 
104             Writer out = create();
105             char[] a = new char[1024];
106             out.write(a, 1000, 0);
107             out.write(a, 0, 0);
108             out.write(new char[] { });
109 
110             out.close();
111             assertArrayEquals(expected, getChars());
112         }
113 
sinkTestWriteCharByChar()114         public void sinkTestWriteCharByChar() throws Exception {
115             char[] expected = "EFGCDECBA".toCharArray();
116 
117             Writer out = create();
118             for (char c : expected) {
119                 out.write(c);
120             }
121 
122             out.close();
123             assertArrayEquals(expected, getChars());
124         }
125 
sinkTestWriteArray()126         public void sinkTestWriteArray() throws Exception {
127             char[] expected = "EFGCDECBA".toCharArray();
128 
129             Writer out = create();
130 
131             out.write("EF".toCharArray());
132             out.write("GCDE".toCharArray());
133             out.write("CBA".toCharArray());
134 
135             out.close();
136             assertArrayEquals(expected, getChars());
137         }
138 
sinkTestWriteOffset()139         public void sinkTestWriteOffset() throws Exception {
140             char[] expected = "EFGCDECBA".toCharArray();
141             Writer out = create();
142 
143             char[] a = new char[1024];
144             a[1000] = 'E';
145             a[1001] = 'F';
146             out.write(a, 1000, 2);
147 
148             char[] b = new char[1024];
149             b[1020] = 'G';
150             b[1021] = 'C';
151             b[1022] = 'D';
152             b[1023] = 'E';
153             out.write(b, 1020, 4);
154 
155             char[] c = new char[1024];
156             c[0] = 'C';
157             c[1] = 'B';
158             c[2] = 'A';
159             out.write(c, 0, 3);
160 
161             out.close();
162             assertArrayEquals(expected, getChars());
163         }
164 
sinkTestWriteLargeArray()165         public void sinkTestWriteLargeArray() throws Exception {
166             Random dice = new Random();
167             char[] expected = new char[(1024 * 1024) + 1]; // 2 MB + 1 char
168             for (int c = 0; c < expected.length; c++) {
169                 expected[c] = (char) ('A' + dice.nextInt(26));
170             }
171 
172             Writer out = create();
173             out.write(expected);
174             out.close();
175 
176             assertArrayEquals(expected, getChars());
177         }
178 
sinkTestWriteAfterClose()179         public void sinkTestWriteAfterClose() throws Exception {
180             char[] expectedChars = "EF".toCharArray();
181             Writer out = create();
182 
183             out.write(expectedChars);
184             out.close();
185 
186             try {
187                 out.write("GCDE".toCharArray());
188                 fail("expected already closed exception");
189             } catch (IOException expected) {
190             }
191 
192             assertArrayEquals(expectedChars, getChars());
193         }
194 
sinkTestWriteAfterCloseSuppressed()195         public void sinkTestWriteAfterCloseSuppressed() throws Exception {
196             Writer out = create();
197             out.write("EF".toCharArray());
198             out.close();
199             out.write("GCDE".toCharArray()); // no exception expected!
200         }
201 
202         // adding a new test? Don't forget to update createTests().
203 
204         @Override
getName()205         public String getName() {
206             return CharSinkTester.this.toString() + ":" + super.getName();
207         }
208     }
209 }
210