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