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 8067661 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 */ 42 public class TransferTo { 43 44 private static Random generator = RandomFactory.getRandom(); 45 46 public static void main(String[] args) throws IOException { 47 ifOutIsNullThenNpeIsThrown(); 48 ifExceptionInInputNeitherSideIsClosed(); 49 ifExceptionInOutputNeitherSideIsClosed(); 50 onReturnNeitherSideIsClosed(); 51 onReturnInputIsAtEnd(); 52 contents(); 53 } 54 55 private static void ifOutIsNullThenNpeIsThrown() throws IOException { 56 try (Reader in = input()) { 57 assertThrowsNPE(() -> in.transferTo(null), "out"); 58 } 59 60 try (Reader in = input((char) 1)) { 61 assertThrowsNPE(() -> in.transferTo(null), "out"); 62 } 63 64 try (Reader in = input((char) 1, (char) 2)) { 65 assertThrowsNPE(() -> in.transferTo(null), "out"); 66 } 67 68 Reader in = null; 69 try { 70 Reader fin = in = new ThrowingReader(); 71 // null check should precede everything else: 72 // Reader shouldn't be touched if Writer is null 73 assertThrowsNPE(() -> fin.transferTo(null), "out"); 74 } finally { 75 if (in != null) 76 try { 77 in.close(); 78 } catch (IOException ignored) { } 79 } 80 } 81 82 private static void ifExceptionInInputNeitherSideIsClosed() 83 throws IOException { 84 transferToThenCheckIfAnyClosed(input(0, new char[]{1, 2, 3}), output()); 85 transferToThenCheckIfAnyClosed(input(1, new char[]{1, 2, 3}), output()); 86 transferToThenCheckIfAnyClosed(input(2, new char[]{1, 2, 3}), output()); 87 } 88 89 private static void ifExceptionInOutputNeitherSideIsClosed() 90 throws IOException { 91 transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(0)); 92 transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(1)); 93 transferToThenCheckIfAnyClosed(input(new char[]{1, 2, 3}), output(2)); 94 } 95 96 private static void transferToThenCheckIfAnyClosed(Reader input, 97 Writer output) 98 throws IOException { 99 try (CloseLoggingReader in = new CloseLoggingReader(input); 100 CloseLoggingWriter out = 101 new CloseLoggingWriter(output)) { 102 boolean thrown = false; 103 try { 104 in.transferTo(out); 105 } catch (IOException ignored) { 106 thrown = true; 107 } 108 if (!thrown) 109 throw new AssertionError(); 110 111 if (in.wasClosed() || out.wasClosed()) { 112 throw new AssertionError(); 113 } 114 } 115 } 116 117 private static void onReturnNeitherSideIsClosed() 118 throws IOException { 119 try (CloseLoggingReader in = 120 new CloseLoggingReader(input(new char[]{1, 2, 3})); 121 CloseLoggingWriter out = 122 new CloseLoggingWriter(output())) { 123 124 in.transferTo(out); 125 126 if (in.wasClosed() || out.wasClosed()) { 127 throw new AssertionError(); 128 } 129 } 130 } 131 132 private static void onReturnInputIsAtEnd() throws IOException { 133 try (Reader in = input(new char[]{1, 2, 3}); 134 Writer out = output()) { 135 136 in.transferTo(out); 137 138 if (in.read() != -1) { 139 throw new AssertionError(); 140 } 141 } 142 } 143 144 private static void contents() throws IOException { 145 checkTransferredContents(new char[0]); 146 checkTransferredContents(createRandomChars(1024, 4096)); 147 // to span through several batches 148 checkTransferredContents(createRandomChars(16384, 16384)); 149 } 150 151 private static void checkTransferredContents(char[] chars) 152 throws IOException { 153 try (Reader in = input(chars); 154 StringWriter out = new StringWriter()) { 155 in.transferTo(out); 156 157 char[] outChars = out.toString().toCharArray(); 158 if (!Arrays.equals(chars, outChars)) { 159 throw new AssertionError( 160 format("chars.length=%s, outChars.length=%s", 161 chars.length, outChars.length)); 162 } 163 } 164 } 165 166 private static char[] createRandomChars(int min, int maxRandomAdditive) { 167 char[] chars = new char[min + generator.nextInt(maxRandomAdditive)]; 168 for (int index=0; index<chars.length; index++) { 169 chars[index] = (char)generator.nextInt(); 170 } 171 return chars; 172 } 173 174 private static Writer output() { 175 return output(-1); 176 } 177 178 private static Writer output(int exceptionPosition) { 179 return new Writer() { 180 181 int pos; 182 183 @Override 184 public void write(int b) throws IOException { 185 if (pos++ == exceptionPosition) 186 throw new IOException(); 187 } 188 189 @Override 190 public void write(char[] chars, int off, int len) throws IOException { 191 for (int i=0; i<len; i++) { 192 write(chars[off + i]); 193 } 194 } 195 196 @Override 197 public Writer append(CharSequence csq, int start, int end) throws IOException { 198 for (int i = start; i < end; i++) { 199 write(csq.charAt(i)); 200 } 201 return this; 202 } 203 204 @Override 205 public void flush() throws IOException { 206 } 207 208 @Override 209 public void close() throws IOException { 210 } 211 }; 212 } 213 214 private static Reader input(char... chars) { 215 return input(-1, chars); 216 } 217 218 private static Reader input(int exceptionPosition, char... chars) { 219 return new Reader() { 220 221 int pos; 222 223 @Override 224 public int read() throws IOException { 225 if (pos == exceptionPosition) { 226 throw new IOException(); 227 } 228 229 if (pos >= chars.length) 230 return -1; 231 return chars[pos++]; 232 } 233 234 @Override 235 public int read(char[] cbuf, int off, int len) throws IOException { 236 int c = read(); 237 if (c == -1) { 238 return -1; 239 } 240 cbuf[off] = (char)c; 241 242 int i = 1; 243 for (; i < len ; i++) { 244 c = read(); 245 if (c == -1) { 246 break; 247 } 248 cbuf[off + i] = (char)c; 249 } 250 return i; 251 } 252 253 @Override 254 public void close() throws IOException { 255 } 256 }; 257 } 258 259 private static class ThrowingReader extends Reader { 260 261 boolean closed; 262 263 @Override 264 public int read(char[] b, int off, int len) throws IOException { 265 throw new IOException(); 266 } 267 268 @Override 269 public void close() throws IOException { 270 if (!closed) { 271 closed = true; 272 throw new IOException(); 273 } 274 } 275 @Override 276 public int read() throws IOException { 277 throw new IOException(); 278 } 279 } 280 281 private static class CloseLoggingReader extends FilterReader { 282 283 boolean closed; 284 285 CloseLoggingReader(Reader in) { 286 super(in); 287 } 288 289 @Override 290 public void close() throws IOException { 291 closed = true; 292 super.close(); 293 } 294 295 boolean wasClosed() { 296 return closed; 297 } 298 } 299 300 private static class CloseLoggingWriter extends FilterWriter { 301 302 boolean closed; 303 304 CloseLoggingWriter(Writer out) { 305 super(out); 306 } 307 308 @Override 309 public void close() throws IOException { 310 closed = true; 311 super.close(); 312 } 313 314 boolean wasClosed() { 315 return closed; 316 } 317 } 318 319 public interface Thrower { 320 public void run() throws Throwable; 321 } 322 323 public static void assertThrowsNPE(Thrower thrower, String message) { 324 assertThrows(thrower, NullPointerException.class, message); 325 } 326 327 public static <T extends Throwable> void assertThrows(Thrower thrower, 328 Class<T> throwable, 329 String message) { 330 Throwable thrown; 331 try { 332 thrower.run(); 333 thrown = null; 334 } catch (Throwable caught) { 335 thrown = caught; 336 } 337 338 if (!throwable.isInstance(thrown)) { 339 String caught = thrown == null ? 340 "nothing" : thrown.getClass().getCanonicalName(); 341 throw new AssertionError( 342 format("Expected to catch %s, but caught %s", 343 throwable, caught), thrown); 344 } 345 346 if (thrown != null && !message.equals(thrown.getMessage())) { 347 throw new AssertionError( 348 format("Expected exception message to be '%s', but it's '%s'", 349 message, thrown.getMessage())); 350 } 351 } 352 }