• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.io;
18 
19 import static org.junit.Assert.assertThrows;
20 
21 import com.google.common.base.Strings;
22 import com.google.common.collect.ImmutableList;
23 import java.io.EOFException;
24 import java.io.FilterReader;
25 import java.io.IOException;
26 import java.io.Reader;
27 import java.io.StringReader;
28 import java.io.StringWriter;
29 import java.io.Writer;
30 import java.nio.CharBuffer;
31 import java.util.List;
32 
33 /**
34  * Unit test for {@link CharStreams}.
35  *
36  * @author Chris Nokleberg
37  */
38 public class CharStreamsTest extends IoTestCase {
39 
40   private static final String TEXT = "The quick brown fox jumped over the lazy dog.";
41 
testToString()42   public void testToString() throws IOException {
43     assertEquals(TEXT, CharStreams.toString(new StringReader(TEXT)));
44   }
45 
testReadLines()46   public void testReadLines() throws IOException {
47     List<String> lines = CharStreams.readLines(new StringReader("a\nb\nc"));
48     assertEquals(ImmutableList.of("a", "b", "c"), lines);
49   }
50 
testReadLines_withLineProcessor()51   public void testReadLines_withLineProcessor() throws IOException {
52     String text = "a\nb\nc";
53 
54     // Test a LineProcessor that always returns false.
55     Reader r = new StringReader(text);
56     LineProcessor<Integer> alwaysFalse =
57         new LineProcessor<Integer>() {
58           int seen;
59 
60           @Override
61           public boolean processLine(String line) {
62             seen++;
63             return false;
64           }
65 
66           @Override
67           public Integer getResult() {
68             return seen;
69           }
70         };
71     assertEquals(
72         "processLine was called more than once",
73         1,
74         CharStreams.readLines(r, alwaysFalse).intValue());
75 
76     // Test a LineProcessor that always returns true.
77     r = new StringReader(text);
78     LineProcessor<Integer> alwaysTrue =
79         new LineProcessor<Integer>() {
80           int seen;
81 
82           @Override
83           public boolean processLine(String line) {
84             seen++;
85             return true;
86           }
87 
88           @Override
89           public Integer getResult() {
90             return seen;
91           }
92         };
93     assertEquals(
94         "processLine was not called for all the lines",
95         3,
96         CharStreams.readLines(r, alwaysTrue).intValue());
97 
98     // Test a LineProcessor that is conditional.
99     r = new StringReader(text);
100     final StringBuilder sb = new StringBuilder();
101     LineProcessor<Integer> conditional =
102         new LineProcessor<Integer>() {
103           int seen;
104 
105           @Override
106           public boolean processLine(String line) {
107             seen++;
108             sb.append(line);
109             return seen < 2;
110           }
111 
112           @Override
113           public Integer getResult() {
114             return seen;
115           }
116         };
117     assertEquals(2, CharStreams.readLines(r, conditional).intValue());
118     assertEquals("ab", sb.toString());
119   }
120 
testSkipFully_eof()121   public void testSkipFully_eof() throws IOException {
122     Reader reader = new StringReader("abcde");
123     assertThrows(EOFException.class, () -> CharStreams.skipFully(reader, 6));
124   }
125 
testSkipFully()126   public void testSkipFully() throws IOException {
127     String testString = "abcdef";
128     Reader reader = new StringReader(testString);
129 
130     assertEquals(testString.charAt(0), reader.read());
131     CharStreams.skipFully(reader, 1);
132     assertEquals(testString.charAt(2), reader.read());
133     CharStreams.skipFully(reader, 2);
134     assertEquals(testString.charAt(5), reader.read());
135 
136     assertEquals(-1, reader.read());
137   }
138 
testAsWriter()139   public void testAsWriter() {
140     // Should wrap Appendable in a new object
141     Appendable plainAppendable = new StringBuilder();
142     Writer result = CharStreams.asWriter(plainAppendable);
143     assertNotSame(plainAppendable, result);
144     assertNotNull(result);
145 
146     // A Writer should not be wrapped
147     Appendable secretlyAWriter = new StringWriter();
148     result = CharStreams.asWriter(secretlyAWriter);
149     assertSame(secretlyAWriter, result);
150   }
151 
152   // CharStreams.copy has type specific optimizations for Readers,StringBuilders and Writers
153 
testCopy()154   public void testCopy() throws IOException {
155     StringBuilder builder = new StringBuilder();
156     long copied =
157         CharStreams.copy(
158             wrapAsGenericReadable(new StringReader(ASCII)), wrapAsGenericAppendable(builder));
159     assertEquals(ASCII, builder.toString());
160     assertEquals(ASCII.length(), copied);
161 
162     StringBuilder builder2 = new StringBuilder();
163     copied =
164         CharStreams.copy(
165             wrapAsGenericReadable(new StringReader(I18N)), wrapAsGenericAppendable(builder2));
166     assertEquals(I18N, builder2.toString());
167     assertEquals(I18N.length(), copied);
168   }
169 
testCopy_toStringBuilder_fromReader()170   public void testCopy_toStringBuilder_fromReader() throws IOException {
171     StringBuilder builder = new StringBuilder();
172     long copied = CharStreams.copy(new StringReader(ASCII), builder);
173     assertEquals(ASCII, builder.toString());
174     assertEquals(ASCII.length(), copied);
175 
176     StringBuilder builder2 = new StringBuilder();
177     copied = CharStreams.copy(new StringReader(I18N), builder2);
178     assertEquals(I18N, builder2.toString());
179     assertEquals(I18N.length(), copied);
180   }
181 
testCopy_toStringBuilder_fromReadable()182   public void testCopy_toStringBuilder_fromReadable() throws IOException {
183     StringBuilder builder = new StringBuilder();
184     long copied = CharStreams.copy(wrapAsGenericReadable(new StringReader(ASCII)), builder);
185     assertEquals(ASCII, builder.toString());
186     assertEquals(ASCII.length(), copied);
187 
188     StringBuilder builder2 = new StringBuilder();
189     copied = CharStreams.copy(wrapAsGenericReadable(new StringReader(I18N)), builder2);
190     assertEquals(I18N, builder2.toString());
191     assertEquals(I18N.length(), copied);
192   }
193 
testCopy_toWriter_fromReader()194   public void testCopy_toWriter_fromReader() throws IOException {
195     StringWriter writer = new StringWriter();
196     long copied = CharStreams.copy(new StringReader(ASCII), writer);
197     assertEquals(ASCII, writer.toString());
198     assertEquals(ASCII.length(), copied);
199 
200     StringWriter writer2 = new StringWriter();
201     copied = CharStreams.copy(new StringReader(I18N), writer2);
202     assertEquals(I18N, writer2.toString());
203     assertEquals(I18N.length(), copied);
204   }
205 
testCopy_toWriter_fromReadable()206   public void testCopy_toWriter_fromReadable() throws IOException {
207     StringWriter writer = new StringWriter();
208     long copied = CharStreams.copy(wrapAsGenericReadable(new StringReader(ASCII)), writer);
209     assertEquals(ASCII, writer.toString());
210     assertEquals(ASCII.length(), copied);
211 
212     StringWriter writer2 = new StringWriter();
213     copied = CharStreams.copy(wrapAsGenericReadable(new StringReader(I18N)), writer2);
214     assertEquals(I18N, writer2.toString());
215     assertEquals(I18N.length(), copied);
216   }
217 
218   /**
219    * Test for Guava issue 1061: http://code.google.com/p/guava-libraries/issues/detail?id=1061
220    *
221    * <p>CharStreams.copy was failing to clear its CharBuffer after each read call, which effectively
222    * reduced the available size of the buffer each time a call to read didn't fill up the available
223    * space in the buffer completely. In general this is a performance problem since the buffer size
224    * is permanently reduced, but with certain Reader implementations it could also cause the buffer
225    * size to reach 0, causing an infinite loop.
226    */
testCopyWithReaderThatDoesNotFillBuffer()227   public void testCopyWithReaderThatDoesNotFillBuffer() throws IOException {
228     // need a long enough string for the buffer to hit 0 remaining before the copy completes
229     String string = Strings.repeat("0123456789", 100);
230     StringBuilder b = new StringBuilder();
231     // the main assertion of this test is here... the copy will fail if the buffer size goes down
232     // each time it is not filled completely
233     long copied = CharStreams.copy(newNonBufferFillingReader(new StringReader(string)), b);
234     assertEquals(string, b.toString());
235     assertEquals(string.length(), copied);
236   }
237 
testExhaust_reader()238   public void testExhaust_reader() throws IOException {
239     Reader reader = new StringReader(ASCII);
240     assertEquals(ASCII.length(), CharStreams.exhaust(reader));
241     assertEquals(-1, reader.read());
242     assertEquals(0, CharStreams.exhaust(reader));
243 
244     Reader empty = new StringReader("");
245     assertEquals(0, CharStreams.exhaust(empty));
246     assertEquals(-1, empty.read());
247   }
248 
testExhaust_readable()249   public void testExhaust_readable() throws IOException {
250     CharBuffer buf = CharBuffer.wrap(ASCII);
251     assertEquals(ASCII.length(), CharStreams.exhaust(buf));
252     assertEquals(0, buf.remaining());
253     assertEquals(0, CharStreams.exhaust(buf));
254 
255     CharBuffer empty = CharBuffer.wrap("");
256     assertEquals(0, CharStreams.exhaust(empty));
257     assertEquals(0, empty.remaining());
258   }
259 
testNullWriter()260   public void testNullWriter() throws Exception {
261     // create a null writer
262     Writer nullWriter = CharStreams.nullWriter();
263     // write to the writer
264     nullWriter.write('n');
265     String test = "Test string for NullWriter";
266     nullWriter.write(test);
267     nullWriter.write(test, 2, 10);
268     nullWriter.append(null);
269     nullWriter.append(null, 0, 4);
270 
271     assertThrows(IndexOutOfBoundsException.class, () -> nullWriter.append(null, -1, 4));
272 
273     assertThrows(IndexOutOfBoundsException.class, () -> nullWriter.append(null, 0, 5));
274 
275     // nothing really to assert?
276     assertSame(CharStreams.nullWriter(), CharStreams.nullWriter());
277   }
278 
279   /**
280    * Returns a reader wrapping the given reader that only reads half of the maximum number of
281    * characters that it could read in read(char[], int, int).
282    */
newNonBufferFillingReader(Reader reader)283   private static Reader newNonBufferFillingReader(Reader reader) {
284     return new FilterReader(reader) {
285       @Override
286       public int read(char[] cbuf, int off, int len) throws IOException {
287         // if a buffer isn't being cleared correctly, this method will eventually start being called
288         // with a len of 0 forever
289         if (len <= 0) {
290           fail("read called with a len of " + len);
291         }
292         // read fewer than the max number of chars to read
293         // shouldn't be a problem unless the buffer is shrinking each call
294         return in.read(cbuf, off, Math.max(len - 1024, 0));
295       }
296     };
297   }
298 
299   /** Wrap an appendable in an appendable to defeat any type specific optimizations. */
300   private static Appendable wrapAsGenericAppendable(final Appendable a) {
301     return new Appendable() {
302 
303       @Override
304       public Appendable append(CharSequence csq) throws IOException {
305         a.append(csq);
306         return this;
307       }
308 
309       @Override
310       public Appendable append(CharSequence csq, int start, int end) throws IOException {
311         a.append(csq, start, end);
312         return this;
313       }
314 
315       @Override
316       public Appendable append(char c) throws IOException {
317         a.append(c);
318         return this;
319       }
320     };
321   }
322 
323   /** Wrap a readable in a readable to defeat any type specific optimizations. */
324   private static Readable wrapAsGenericReadable(final Readable a) {
325     return new Readable() {
326       @Override
327       public int read(CharBuffer cb) throws IOException {
328         return a.read(cb);
329       }
330     };
331   }
332 }
333