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 com.google.common.base.Charsets.UTF_8; 20 import static com.google.common.io.CharStreams.copy; 21 import static com.google.common.io.CharStreams.newReaderSupplier; 22 23 import com.google.common.base.Charsets; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableSet; 26 import com.google.common.testing.TestLogHandler; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.EOFException; 30 import java.io.FilterReader; 31 import java.io.FilterWriter; 32 import java.io.IOException; 33 import java.io.InputStreamReader; 34 import java.io.Reader; 35 import java.io.StringReader; 36 import java.io.StringWriter; 37 import java.io.Writer; 38 import java.util.List; 39 40 /** 41 * Unit test for {@link CharStreams}. 42 * 43 * @author Chris Nokleberg 44 */ 45 public class CharStreamsTest extends IoTestCase { 46 private static final String TEXT 47 = "The quick brown fox jumped over the lazy dog."; 48 49 static final InputSupplier<? extends Reader> BROKEN_READ 50 = CharStreams.newReaderSupplier(ByteStreamsTest.BROKEN_READ, UTF_8); 51 52 static final OutputSupplier<? extends Writer> BROKEN_WRITE 53 = CharStreams.newWriterSupplier(ByteStreamsTest.BROKEN_WRITE, UTF_8); 54 55 static final InputSupplier<? extends Reader> BROKEN_CLOSE_INPUT 56 = CharStreams.newReaderSupplier(ByteStreamsTest.BROKEN_CLOSE_INPUT, UTF_8); 57 58 static final OutputSupplier<? extends Writer> BROKEN_CLOSE_OUTPUT 59 = CharStreams.newWriterSupplier(ByteStreamsTest.BROKEN_CLOSE_OUTPUT, UTF_8); 60 61 static final InputSupplier<? extends Reader> BROKEN_GET_INPUT 62 = CharStreams.newReaderSupplier(ByteStreamsTest.BROKEN_GET_INPUT, UTF_8); 63 64 static final OutputSupplier<? extends Writer> BROKEN_GET_OUTPUT 65 = CharStreams.newWriterSupplier(ByteStreamsTest.BROKEN_GET_OUTPUT, UTF_8); 66 67 private static final ImmutableSet<InputSupplier<? extends Reader>> BROKEN_INPUTS = 68 ImmutableSet.of(BROKEN_CLOSE_INPUT, BROKEN_GET_INPUT, BROKEN_READ); 69 private static final ImmutableSet<OutputSupplier<? extends Writer>> BROKEN_OUTPUTS 70 = ImmutableSet.of(BROKEN_CLOSE_OUTPUT, BROKEN_GET_OUTPUT, BROKEN_WRITE); 71 72 public void testToString() throws IOException { 73 assertEquals(TEXT, CharStreams.toString(new StringReader(TEXT))); 74 assertEquals(TEXT, 75 CharStreams.toString(CharStreams.newReaderSupplier(TEXT))); 76 } 77 78 public void testSkipFully_blockingRead() throws IOException { 79 Reader reader = new NonSkippingReader("abcdef"); 80 CharStreams.skipFully(reader, 6); 81 assertEquals(-1, reader.read()); 82 } 83 84 private static class NonSkippingReader extends StringReader { 85 NonSkippingReader(String s) { 86 super(s); 87 } 88 89 @Override 90 public long skip(long n) { 91 return 0; 92 } 93 } 94 95 public void testReadLines_fromReadable() throws IOException { 96 byte[] bytes = "a\nb\nc".getBytes(Charsets.UTF_8.name()); 97 List<String> lines = CharStreams.readLines( 98 new InputStreamReader(new ByteArrayInputStream(bytes), Charsets.UTF_8)); 99 assertEquals(ImmutableList.of("a", "b", "c"), lines); 100 } 101 102 public void testReadLines_withLineProcessor() throws IOException { 103 InputSupplier<StringReader> r = CharStreams.newReaderSupplier("a\nb\nc"); 104 105 // Test a LineProcessor that always returns false. 106 LineProcessor<Integer> alwaysFalse = new LineProcessor<Integer>() { 107 int seen; 108 @Override 109 public boolean processLine(String line) { 110 seen++; 111 return false; 112 } 113 @Override 114 public Integer getResult() { 115 return seen; 116 } 117 }; 118 assertEquals("processLine was called more than once", 1, 119 CharStreams.readLines(r, alwaysFalse).intValue()); 120 121 // Test a LineProcessor that always returns true. 122 LineProcessor<Integer> alwaysTrue = new LineProcessor<Integer>() { 123 int seen; 124 @Override 125 public boolean processLine(String line) { 126 seen++; 127 return true; 128 } 129 @Override 130 public Integer getResult() { 131 return seen; 132 } 133 }; 134 assertEquals("processLine was not called for all the lines", 3, 135 CharStreams.readLines(r, alwaysTrue).intValue()); 136 137 // Test a LineProcessor that is conditional. 138 final StringBuilder sb = new StringBuilder(); 139 LineProcessor<Integer> conditional = new LineProcessor<Integer>() { 140 int seen; 141 @Override 142 public boolean processLine(String line) { 143 seen++; 144 sb.append(line); 145 return seen < 2; 146 } 147 @Override 148 public Integer getResult() { 149 return seen; 150 } 151 }; 152 assertEquals(2, CharStreams.readLines(r, conditional).intValue()); 153 assertEquals("ab", sb.toString()); 154 } 155 156 public void testAlwaysCloses() throws IOException { 157 CheckCloseSupplier.Input<Reader> okRead 158 = newCheckReader(CharStreams.newReaderSupplier(TEXT)); 159 CheckCloseSupplier.Output<Writer> okWrite 160 = newCheckWriter(new OutputSupplier<Writer>() { 161 @Override 162 public Writer getOutput() { 163 return new StringWriter(); 164 } 165 }); 166 CheckCloseSupplier.Input<Reader> brokenRead = newCheckReader(BROKEN_READ); 167 CheckCloseSupplier.Output<Writer> brokenWrite 168 = newCheckWriter(BROKEN_WRITE); 169 170 CharStreams.copy(okRead, okWrite); 171 assertTrue(okRead.areClosed()); 172 assertTrue(okWrite.areClosed()); 173 174 try { 175 CharStreams.copy(okRead, brokenWrite); 176 fail("expected exception"); 177 } catch (Exception e) { 178 assertEquals("broken write", e.getMessage()); 179 } 180 assertTrue(okRead.areClosed()); 181 assertTrue(brokenWrite.areClosed()); 182 183 try { 184 CharStreams.copy(brokenRead, okWrite); 185 fail("expected exception"); 186 } catch (Exception e) { 187 assertEquals("broken read", e.getMessage()); 188 } 189 assertTrue(brokenRead.areClosed()); 190 assertTrue(okWrite.areClosed()); 191 192 try { 193 CharStreams.copy(brokenRead, brokenWrite); 194 fail("expected exception"); 195 } catch (Exception e) { 196 assertEquals("broken read", e.getMessage()); 197 } 198 assertTrue(brokenRead.areClosed()); 199 assertTrue(brokenWrite.areClosed()); 200 201 assertEquals(TEXT, CharStreams.toString(okRead)); 202 assertTrue(okRead.areClosed()); 203 204 try { 205 CharStreams.toString(brokenRead); 206 fail("expected exception"); 207 } catch (Exception e) { 208 assertEquals("broken read", e.getMessage()); 209 } 210 assertTrue(brokenRead.areClosed()); 211 212 try { 213 CharStreams.write("hello world", brokenWrite); 214 fail("expected exception"); 215 } catch (Exception e) { 216 assertEquals("broken write", e.getMessage()); 217 } 218 assertTrue(brokenWrite.areClosed()); 219 } 220 221 private static int getAndResetRecords(TestLogHandler logHandler) { 222 int records = logHandler.getStoredLogRecords().size(); 223 logHandler.clear(); 224 return records; 225 } 226 227 private static void runFailureTest( 228 InputSupplier<? extends Reader> in, OutputSupplier<? extends Writer> out) { 229 try { 230 copy(in, out); 231 fail(); 232 } catch (IOException expected) { 233 } 234 } 235 236 private static OutputSupplier<Writer> newStringWriterSupplier() { 237 return new OutputSupplier<Writer>() { 238 @Override public Writer getOutput() { 239 return new StringWriter(); 240 } 241 }; 242 } 243 244 public void testSkipFully_EOF() throws IOException { 245 Reader reader = new StringReader("abcde"); 246 try { 247 CharStreams.skipFully(reader, 6); 248 fail("expected EOFException"); 249 } catch (EOFException e) { 250 // expected 251 } 252 } 253 254 public void testSkipFully() throws IOException { 255 String testString = "abcdef"; 256 Reader reader = new StringReader(testString); 257 258 assertEquals(testString.charAt(0), reader.read()); 259 CharStreams.skipFully(reader, 1); 260 assertEquals(testString.charAt(2), reader.read()); 261 CharStreams.skipFully(reader, 2); 262 assertEquals(testString.charAt(5), reader.read()); 263 264 assertEquals(-1, reader.read()); 265 } 266 267 public void testAsWriter() { 268 // Should wrap Appendable in a new object 269 Appendable plainAppendable = new StringBuilder(); 270 Writer result = CharStreams.asWriter(plainAppendable); 271 assertNotSame(plainAppendable, result); 272 assertNotNull(result); 273 274 // A Writer should not be wrapped 275 Appendable secretlyAWriter = new StringWriter(); 276 result = CharStreams.asWriter(secretlyAWriter); 277 assertSame(secretlyAWriter, result); 278 } 279 280 public void testWriteString() throws IOException { 281 final StringWriter sw = new StringWriter(); 282 String expected = "foo"; 283 CharStreams.write(expected, new OutputSupplier<Writer>() { 284 @Override public Writer getOutput() { 285 return sw; 286 } 287 }); 288 assertEquals(expected, sw.toString()); 289 } 290 291 private static CheckCloseSupplier.Input<Reader> newCheckReader( 292 InputSupplier<? extends Reader> delegate) { 293 return new CheckCloseSupplier.Input<Reader>(delegate) { 294 @Override protected Reader wrap(Reader object, final Callback callback) { 295 return new FilterReader(object) { 296 @Override public void close() throws IOException { 297 callback.delegateClosed(); 298 super.close(); 299 } 300 }; 301 } 302 }; 303 } 304 305 private static CheckCloseSupplier.Output<Writer> newCheckWriter( 306 OutputSupplier<? extends Writer> delegate) { 307 return new CheckCloseSupplier.Output<Writer>(delegate) { 308 @Override protected Writer wrap(Writer object, final Callback callback) { 309 return new FilterWriter(object) { 310 @Override public void close() throws IOException { 311 callback.delegateClosed(); 312 super.close(); 313 } 314 }; 315 } 316 }; 317 } 318 } 319