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