1 /* 2 * Copyright (c) 2014, 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 package test.java.io.InputStream; 24 25 import java.io.ByteArrayOutputStream; 26 import java.io.FilterInputStream; 27 import java.io.FilterOutputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.OutputStream; 31 import java.util.Arrays; 32 import java.util.Random; 33 import org.testng.annotations.Test; 34 35 import static java.lang.String.format; 36 37 /* 38 * @test 39 * @bug 8066867 40 * @summary tests whether java.io.InputStream.transferTo conforms to its 41 * contract defined in the javadoc 42 * @key randomness 43 */ 44 public class TransferTo { 45 46 @Test ifOutIsNullThenNpeIsThrown()47 public void ifOutIsNullThenNpeIsThrown() throws IOException { 48 try (InputStream in = input()) { 49 assertThrowsNPE(() -> in.transferTo(null), "out"); 50 } 51 52 try (InputStream in = input((byte) 1)) { 53 assertThrowsNPE(() -> in.transferTo(null), "out"); 54 } 55 56 try (InputStream in = input((byte) 1, (byte) 2)) { 57 assertThrowsNPE(() -> in.transferTo(null), "out"); 58 } 59 60 InputStream in = null; 61 try { 62 InputStream fin = in = new ThrowingInputStream(); 63 // null check should precede everything else: 64 // InputStream shouldn't be touched if OutputStream is null 65 assertThrowsNPE(() -> fin.transferTo(null), "out"); 66 } finally { 67 if (in != null) 68 try { 69 in.close(); 70 } catch (IOException ignored) { } 71 } 72 } 73 74 @Test ifExceptionInInputNeitherStreamIsClosed()75 public void ifExceptionInInputNeitherStreamIsClosed() 76 throws IOException { 77 transferToThenCheckIfAnyClosed(input(0, new byte[]{1, 2, 3}), output()); 78 transferToThenCheckIfAnyClosed(input(1, new byte[]{1, 2, 3}), output()); 79 transferToThenCheckIfAnyClosed(input(2, new byte[]{1, 2, 3}), output()); 80 } 81 82 @Test ifExceptionInOutputNeitherStreamIsClosed()83 public void ifExceptionInOutputNeitherStreamIsClosed() 84 throws IOException { 85 transferToThenCheckIfAnyClosed(input(new byte[]{1, 2, 3}), output(0)); 86 transferToThenCheckIfAnyClosed(input(new byte[]{1, 2, 3}), output(1)); 87 transferToThenCheckIfAnyClosed(input(new byte[]{1, 2, 3}), output(2)); 88 } 89 transferToThenCheckIfAnyClosed(InputStream input, OutputStream output)90 private static void transferToThenCheckIfAnyClosed(InputStream input, 91 OutputStream output) 92 throws IOException { 93 try (CloseLoggingInputStream in = new CloseLoggingInputStream(input); 94 CloseLoggingOutputStream out = 95 new CloseLoggingOutputStream(output)) { 96 boolean thrown = false; 97 try { 98 in.transferTo(out); 99 } catch (IOException ignored) { 100 thrown = true; 101 } 102 if (!thrown) 103 throw new AssertionError(); 104 105 if (in.wasClosed() || out.wasClosed()) { 106 throw new AssertionError(); 107 } 108 } 109 } 110 111 @Test onReturnNeitherStreamIsClosed()112 public void onReturnNeitherStreamIsClosed() 113 throws IOException { 114 try (CloseLoggingInputStream in = 115 new CloseLoggingInputStream(input(new byte[]{1, 2, 3})); 116 CloseLoggingOutputStream out = 117 new CloseLoggingOutputStream(output())) { 118 119 in.transferTo(out); 120 121 if (in.wasClosed() || out.wasClosed()) { 122 throw new AssertionError(); 123 } 124 } 125 } 126 127 @Test onReturnInputIsAtEnd()128 public void onReturnInputIsAtEnd() throws IOException { 129 try (InputStream in = input(new byte[]{1, 2, 3}); 130 OutputStream out = output()) { 131 132 in.transferTo(out); 133 134 if (in.read() != -1) { 135 throw new AssertionError(); 136 } 137 } 138 } 139 140 @Test contents()141 public void contents() throws IOException { 142 checkTransferredContents(new byte[0]); 143 checkTransferredContents(createRandomBytes(1024, 4096)); 144 // to span through several batches 145 checkTransferredContents(createRandomBytes(16384, 16384)); 146 } 147 checkTransferredContents(byte[] bytes)148 private static void checkTransferredContents(byte[] bytes) 149 throws IOException { 150 try (InputStream in = input(bytes); 151 ByteArrayOutputStream out = new ByteArrayOutputStream()) { 152 in.transferTo(out); 153 154 byte[] outBytes = out.toByteArray(); 155 if (!Arrays.equals(bytes, outBytes)) { 156 throw new AssertionError( 157 format("bytes.length=%s, outBytes.length=%s", 158 bytes.length, outBytes.length)); 159 } 160 } 161 } 162 createRandomBytes(int min, int maxRandomAdditive)163 private static byte[] createRandomBytes(int min, int maxRandomAdditive) { 164 Random rnd = new Random(); 165 byte[] bytes = new byte[min + rnd.nextInt(maxRandomAdditive)]; 166 rnd.nextBytes(bytes); 167 return bytes; 168 } 169 output()170 private static OutputStream output() { 171 return output(-1); 172 } 173 output(int exceptionPosition)174 private static OutputStream output(int exceptionPosition) { 175 return new OutputStream() { 176 177 int pos; 178 179 @Override 180 public void write(int b) throws IOException { 181 if (pos++ == exceptionPosition) 182 throw new IOException(); 183 } 184 }; 185 } 186 input(byte... bytes)187 private static InputStream input(byte... bytes) { 188 return input(-1, bytes); 189 } 190 input(int exceptionPosition, byte... bytes)191 private static InputStream input(int exceptionPosition, byte... bytes) { 192 return new InputStream() { 193 194 int pos; 195 196 @Override 197 public int read() throws IOException { 198 if (pos == exceptionPosition) { 199 // because of the pesky IOException swallowing in 200 // java.io.InputStream.read(byte[], int, int) 201 // pos++; 202 throw new IOException(); 203 } 204 205 if (pos >= bytes.length) 206 return -1; 207 return bytes[pos++] & 0xff; 208 } 209 }; 210 } 211 212 private static class ThrowingInputStream extends InputStream { 213 214 boolean closed; 215 216 @Override 217 public int read(byte[] b) throws IOException { 218 throw new IOException(); 219 } 220 221 @Override 222 public int read(byte[] b, int off, int len) throws IOException { 223 throw new IOException(); 224 } 225 226 @Override 227 public long skip(long n) throws IOException { 228 throw new IOException(); 229 } 230 231 @Override 232 public int available() throws IOException { 233 throw new IOException(); 234 } 235 236 @Override 237 public void close() throws IOException { 238 if (!closed) { 239 closed = true; 240 throw new IOException(); 241 } 242 } 243 244 @Override 245 public void reset() throws IOException { 246 throw new IOException(); 247 } 248 249 @Override 250 public int read() throws IOException { 251 throw new IOException(); 252 } 253 } 254 255 private static class CloseLoggingInputStream extends FilterInputStream { 256 257 boolean closed; 258 259 CloseLoggingInputStream(InputStream in) { 260 super(in); 261 } 262 263 @Override 264 public void close() throws IOException { 265 closed = true; 266 super.close(); 267 } 268 269 boolean wasClosed() { 270 return closed; 271 } 272 } 273 274 private static class CloseLoggingOutputStream extends FilterOutputStream { 275 276 boolean closed; 277 278 CloseLoggingOutputStream(OutputStream out) { 279 super(out); 280 } 281 282 @Override 283 public void close() throws IOException { 284 closed = true; 285 super.close(); 286 } 287 288 boolean wasClosed() { 289 return closed; 290 } 291 } 292 293 public interface Thrower { 294 public void run() throws Throwable; 295 } 296 297 public static void assertThrowsNPE(Thrower thrower, String message) { 298 assertThrows(thrower, NullPointerException.class, message); 299 } 300 301 public static <T extends Throwable> void assertThrows(Thrower thrower, 302 Class<T> throwable, 303 String message) { 304 Throwable thrown; 305 try { 306 thrower.run(); 307 thrown = null; 308 } catch (Throwable caught) { 309 thrown = caught; 310 } 311 312 if (!throwable.isInstance(thrown)) { 313 String caught = thrown == null ? 314 "nothing" : thrown.getClass().getCanonicalName(); 315 throw new AssertionError( 316 format("Expected to catch %s, but caught %s", 317 throwable, caught), thrown); 318 } 319 320 if (thrown != null && !message.equals(thrown.getMessage())) { 321 throw new AssertionError( 322 format("Expected exception message to be '%s', but it's '%s'", 323 message, thrown.getMessage())); 324 } 325 } 326 }