1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.*; 25 import java.util.Arrays; 26 import java.util.Random; 27 28 import jdk.test.lib.RandomFactory; 29 30 import static java.lang.String.format; 31 32 /* 33 * @test 34 * @bug 8066870 35 * @summary tests whether java.lang.Readable.transferTo default implementation 36 * conforms to the contract defined in the javadoc 37 * @library /test/lib 38 * @build jdk.test.lib.RandomFactory 39 * @run main TransferTo 40 * @key randomness 41 * @author Patrick Reinhart 42 */ 43 public class TransferTo { 44 45 private static Random generator = RandomFactory.getRandom(); 46 47 public static void main(String[] args) throws IOException { 48 ifOutIsNullThenNpeIsThrown(); 49 ifExceptionInInputNeitherSideIsClosed(); 50 ifExceptionInOutputNeitherSideIsClosed(); 51 onReturnNeitherSideIsClosed(); 52 onReturnInputIsAtEnd(); 53 contents(); 54 } 55 56 private static void ifOutIsNullThenNpeIsThrown() throws IOException { 57 try (Reader in = input()) { 58 assertThrowsNPE(() -> in.transferTo(null), "out"); 59 } 60 61 try (Reader in = input((char) 1)) { 62 assertThrowsNPE(() -> in.transferTo(null), "out"); 63 } 64 65 try (Reader in = input((char) 1, (char) 2)) { 66 assertThrowsNPE(() -> in.transferTo(null), "out"); 67 } 68 69 Reader in = null; 70 try { 71 Reader fin = in = new ThrowingReader(); 72 // null check should precede everything else: 73 // Reader shouldn't be touched if Writer is null 74 assertThrowsNPE(() -> fin.transferTo(null), "out"); 75 } finally { 76 if (in != null) 77 try { 78 in.close(); 79 } catch (IOException ignored) { } 80 } 81 } 82 83 private static void ifExceptionInInputNeitherSideIsClosed() 84 throws IOException { 85 transferToThenCheckIfAnyClosed(input(0, new char[]{1, 2, 3}), output()); 86 transferToThenCheckIfAnyClosed(input(1, new char[]{1, 2, 3}), output()); 87 transferToThenCheckIfAnyClosed(input(2, new char[]{1, 2, 3}), output()); 88 } 89 90 private static void ifExceptionInOutputNeitherSideIsClosed() 91 throws IOException { 92 transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(0)); 93 transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(1)); 94 transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(2)); 95 } 96 97 private static void transferToThenCheckIfAnyClosed(Reader input, 98 Writer output) 99 throws IOException { 100 try (CloseLoggingReader in = new CloseLoggingReader(input); 101 CloseLoggingWriter out = 102 new CloseLoggingWriter(output)) { 103 boolean thrown = false; 104 try { 105 in.transferTo(out); 106 } catch (IOException ignored) { 107 thrown = true; 108 } 109 if (!thrown) 110 throw new AssertionError(); 111 112 if (in.wasClosed() || out.wasClosed()) { 113 throw new AssertionError(); 114 } 115 } 116 } 117 118 private static void onReturnNeitherSideIsClosed() 119 throws IOException { 120 try (CloseLoggingReader in = 121 new CloseLoggingReader(input(new char[]{1, 2, 3})); 122 CloseLoggingWriter out = 123 new CloseLoggingWriter(output())) { 124 125 in.transferTo(out); 126 127 if (in.wasClosed() || out.wasClosed()) { 128 throw new AssertionError(); 129 } 130 } 131 } 132 133 private static void onReturnInputIsAtEnd() throws IOException { 134 try (Reader in = input(new char[]{1, 2, 3}); 135 Writer out = output()) { 136 137 in.transferTo(out); 138 139 if (in.read() != -1) { 140 throw new AssertionError(); 141 } 142 } 143 } 144 145 private static void contents() throws IOException { 146 checkTransferredContents(new char[0]); 147 checkTransferredContents(createRandomChars(1024, 4096)); 148 // to span through several batches 149 checkTransferredContents(createRandomChars(16384, 16384)); 150 } 151 152 private static void checkTransferredContents(char[] chars) 153 throws IOException { 154 try (Reader in = input(chars); 155 StringWriter out = new StringWriter()) { 156 in.transferTo(out); 157 158 char[] outChars = out.toString().toCharArray(); 159 if (!Arrays.equals(chars, outChars)) { 160 throw new AssertionError( 161 format("chars.length=%s, outChars.length=%s", 162 chars.length, outChars.length)); 163 } 164 } 165 } 166 167 private static char[] createRandomChars(int min, int maxRandomAdditive) { 168 char[] chars = new char[min + generator.nextInt(maxRandomAdditive)]; 169 for (int index=0; index<chars.length; index++) { 170 chars[index] = (char)generator.nextInt(); 171 } 172 return chars; 173 } 174 175 private static Writer output() { 176 return output(-1); 177 } 178 179 private static Writer output(int exceptionPosition) { 180 return new Writer() { 181 182 int pos; 183 184 @Override 185 public void write(int b) throws IOException { 186 if (pos++ == exceptionPosition) 187 throw new IOException(); 188 } 189 190 @Override 191 public void write(char[] chars, int off, int len) throws IOException { 192 for (int i=0; i<len; i++) { 193 write(chars[off + i]); 194 } 195 } 196 197 @Override 198 public Writer append(CharSequence csq, int start, int end) throws IOException { 199 for (int i = start; i < end; i++) { 200 write(csq.charAt(i)); 201 } 202 return this; 203 } 204 205 @Override 206 public void flush() throws IOException { 207 } 208 209 @Override 210 public void close() throws IOException { 211 } 212 }; 213 } 214 215 private static Reader input(char... chars) { 216 return input(-1, chars); 217 } 218 219 private static Reader input(int exceptionPosition, char... chars) { 220 return new Reader() { 221 222 int pos; 223 224 @Override 225 public int read() throws IOException { 226 if (pos == exceptionPosition) { 227 throw new IOException(); 228 } 229 230 if (pos >= chars.length) 231 return -1; 232 return chars[pos++]; 233 } 234 235 @Override 236 public int read(char[] cbuf, int off, int len) throws IOException { 237 int c = read(); 238 if (c == -1) { 239 return -1; 240 } 241 cbuf[off] = (char)c; 242 243 int i = 1; 244 for (; i < len ; i++) { 245 c = read(); 246 if (c == -1) { 247 break; 248 } 249 cbuf[off + i] = (char)c; 250 } 251 return i; 252 } 253 254 @Override 255 public void close() throws IOException { 256 } 257 }; 258 } 259 260 private static class ThrowingReader extends Reader { 261 262 boolean closed; 263 264 @Override 265 public int read(char[] b, int off, int len) throws IOException { 266 throw new IOException(); 267 } 268 269 @Override 270 public void close() throws IOException { 271 if (!closed) { 272 closed = true; 273 throw new IOException(); 274 } 275 } 276 @Override 277 public int read() throws IOException { 278 throw new IOException(); 279 } 280 } 281 282 private static class CloseLoggingReader extends FilterReader { 283 284 boolean closed; 285 286 CloseLoggingReader(Reader in) { 287 super(in); 288 } 289 290 @Override 291 public void close() throws IOException { 292 closed = true; 293 super.close(); 294 } 295 296 boolean wasClosed() { 297 return closed; 298 } 299 } 300 301 private static class CloseLoggingWriter extends FilterWriter { 302 303 boolean closed; 304 305 CloseLoggingWriter(Writer out) { 306 super(out); 307 } 308 309 @Override 310 public void close() throws IOException { 311 closed = true; 312 super.close(); 313 } 314 315 boolean wasClosed() { 316 return closed; 317 } 318 } 319 320 public interface Thrower { 321 public void run() throws Throwable; 322 } 323 324 public static void assertThrowsNPE(Thrower thrower, String message) { 325 assertThrows(thrower, NullPointerException.class, message); 326 } 327 328 public static <T extends Throwable> void assertThrows(Thrower thrower, 329 Class<T> throwable, 330 String message) { 331 Throwable thrown; 332 try { 333 thrower.run(); 334 thrown = null; 335 } catch (Throwable caught) { 336 thrown = caught; 337 } 338 339 if (!throwable.isInstance(thrown)) { 340 String caught = thrown == null ? 341 "nothing" : thrown.getClass().getCanonicalName(); 342 throw new AssertionError( 343 format("Expected to catch %s, but caught %s", 344 throwable, caught), thrown); 345 } 346 347 if (thrown != null && !message.equals(thrown.getMessage())) { 348 throw new AssertionError( 349 format("Expected exception message to be '%s', but it's '%s'", 350 message, thrown.getMessage())); 351 } 352 } 353 }