View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.io;
18  
19  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
20  import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertFalse;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNotSame;
25  import static org.junit.jupiter.api.Assertions.assertNull;
26  import static org.junit.jupiter.api.Assertions.assertSame;
27  import static org.junit.jupiter.api.Assertions.assertThrows;
28  import static org.junit.jupiter.api.Assertions.assertTrue;
29  import static org.junit.jupiter.api.Assertions.fail;
30  import static org.mockito.Mockito.mock;
31  import static org.mockito.Mockito.when;
32  
33  import java.io.BufferedInputStream;
34  import java.io.BufferedOutputStream;
35  import java.io.BufferedReader;
36  import java.io.BufferedWriter;
37  import java.io.ByteArrayInputStream;
38  import java.io.ByteArrayOutputStream;
39  import java.io.CharArrayReader;
40  import java.io.CharArrayWriter;
41  import java.io.Closeable;
42  import java.io.EOFException;
43  import java.io.File;
44  import java.io.FileInputStream;
45  import java.io.IOException;
46  import java.io.InputStream;
47  import java.io.InputStreamReader;
48  import java.io.OutputStream;
49  import java.io.Reader;
50  import java.io.SequenceInputStream;
51  import java.io.StringReader;
52  import java.io.Writer;
53  import java.lang.reflect.InvocationTargetException;
54  import java.net.ServerSocket;
55  import java.net.Socket;
56  import java.net.URI;
57  import java.net.URL;
58  import java.net.URLConnection;
59  import java.nio.ByteBuffer;
60  import java.nio.channels.FileChannel;
61  import java.nio.channels.Selector;
62  import java.nio.charset.Charset;
63  import java.nio.charset.StandardCharsets;
64  import java.nio.file.Files;
65  import java.nio.file.Path;
66  import java.util.Arrays;
67  import java.util.Collections;
68  import java.util.List;
69  import java.util.Objects;
70  import java.util.concurrent.atomic.AtomicBoolean;
71  import java.util.function.Consumer;
72  import java.util.function.Supplier;
73  import java.util.stream.Stream;
74  
75  import org.apache.commons.io.function.IOConsumer;
76  import org.apache.commons.io.input.BrokenInputStream;
77  import org.apache.commons.io.input.CharSequenceInputStream;
78  import org.apache.commons.io.input.CircularInputStream;
79  import org.apache.commons.io.input.NullInputStream;
80  import org.apache.commons.io.input.NullReader;
81  import org.apache.commons.io.output.AppendableWriter;
82  import org.apache.commons.io.output.BrokenOutputStream;
83  import org.apache.commons.io.output.CountingOutputStream;
84  import org.apache.commons.io.output.NullOutputStream;
85  import org.apache.commons.io.output.NullWriter;
86  import org.apache.commons.io.output.StringBuilderWriter;
87  import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
88  import org.apache.commons.io.test.TestUtils;
89  import org.apache.commons.io.test.ThrowOnCloseReader;
90  import org.apache.commons.lang3.JavaVersion;
91  import org.apache.commons.lang3.StringUtils;
92  import org.apache.commons.lang3.SystemUtils;
93  import org.apache.commons.lang3.exception.ExceptionUtils;
94  import org.junit.jupiter.api.AfterAll;
95  import org.junit.jupiter.api.BeforeAll;
96  import org.junit.jupiter.api.BeforeEach;
97  import org.junit.jupiter.api.Disabled;
98  import org.junit.jupiter.api.Test;
99  import org.junit.jupiter.api.io.TempDir;
100 import org.junit.jupiter.params.ParameterizedTest;
101 import org.junit.jupiter.params.provider.Arguments;
102 import org.junit.jupiter.params.provider.MethodSource;
103 import org.mockito.ArgumentMatchers;
104 import org.mockito.MockedStatic;
105 import org.mockito.Mockito;
106 
107 /**
108  * This is used to test {@link IOUtils} for correctness. The following checks are performed:
109  * <ul>
110  * <li>The return must not be null, must be the same type and equals() to the method's second arg</li>
111  * <li>All bytes must have been read from the source (available() == 0)</li>
112  * <li>The source and destination content must be identical (byte-wise comparison check)</li>
113  * <li>The output stream must not have been closed (a byte/char is written to test this, and subsequent size
114  * checked)</li>
115  * </ul>
116  * Due to interdependencies in IOUtils and IOUtilsTest, one bug may cause multiple tests to fail.
117  */
118 @SuppressWarnings("deprecation") // deliberately testing deprecated code
119 class IOUtilsTest {
120 
121     private static final String UTF_8 = StandardCharsets.UTF_8.name();
122 
123     private static final int FILE_SIZE = 1024 * 4 + 1;
124 
125     /** Determine if this is windows. */
126     private static final boolean WINDOWS = File.separatorChar == '\\';
127 
128     /*
129      * Note: this is not particularly beautiful code. A better way to check for flush and close status would be to
130      * implement "trojan horse" wrapper implementations of the various stream classes, which set a flag when relevant
131      * methods are called. (JT)
132      */
133 
134     @BeforeAll
135     @AfterAll
136     public static void beforeAll() {
137         // Not required, just to exercise the method and make sure there are no adverse side-effect when recycling thread locals.
138         IO.clear();
139     }
140 
141     static Stream<Arguments> invalidRead_InputStream_Offset_ArgumentsProvider() {
142         final InputStream input = new ByteArrayInputStream(new byte[10]);
143         final byte[] b = new byte[10];
144         return Stream.of(
145             // input is null
146             Arguments.of(null, b, 0, 1, NullPointerException.class),
147             // b is null
148             Arguments.of(input, null, 0, 1, NullPointerException.class),
149             // off is negative
150             Arguments.of(input, b, -1, 1, IndexOutOfBoundsException.class),
151             // len is negative
152             Arguments.of(input, b, 0, -1, IndexOutOfBoundsException.class),
153             // off + len is too big
154             Arguments.of(input, b, 1, 10, IndexOutOfBoundsException.class),
155             // off + len is too big
156             Arguments.of(input, b, 10, 1, IndexOutOfBoundsException.class)
157         );
158     }
159 
160     static Stream<Arguments> testCheckFromIndexSizeInvalidCases() {
161         return Stream.of(
162                 Arguments.of(-1, 0, 42),
163                 Arguments.of(0, -1, 42),
164                 Arguments.of(0, 0, -1),
165                 // off + len > arrayLength
166                 Arguments.of(1, 42, 42),
167                 Arguments.of(Integer.MAX_VALUE, 1, Integer.MAX_VALUE)
168         );
169     }
170 
171     static Stream<Arguments> testCheckFromIndexSizeValidCases() {
172         return Stream.of(
173                 // Valid cases
174                 Arguments.of(0, 0, 42),
175                 Arguments.of(0, 1, 42),
176                 Arguments.of(0, 42, 42),
177                 Arguments.of(41, 1, 42),
178                 Arguments.of(42, 0, 42)
179         );
180     }
181 
182     static Stream<Arguments> testCheckFromToIndexInvalidCases() {
183         return Stream.of(
184                 Arguments.of(-1, 0, 42),
185                 Arguments.of(0, -1, 42),
186                 Arguments.of(0, 0, -1),
187                 // from > to
188                 Arguments.of(1, 0, 42),
189                 // to > arrayLength
190                 Arguments.of(0, 43, 42),
191                 Arguments.of(1, 43, 42)
192         );
193     }
194 
195     static Stream<Arguments> testCheckFromToIndexValidCases() {
196         return Stream.of(
197                 // Valid cases
198                 Arguments.of(0, 0, 42),
199                 Arguments.of(0, 1, 42),
200                 Arguments.of(0, 42, 42),
201                 Arguments.of(41, 42, 42),
202                 Arguments.of(42, 42, 42)
203         );
204     }
205 
206     private static Stream<Arguments> testToByteArray_InputStream_Size_BufferSize_Succeeds() {
207         final byte[] data = new byte[1024];
208         for (int i = 0; i < 1024; i++) {
209             data[i] = (byte) i;
210         }
211         return Stream.of(
212                 // Eager reading
213                 Arguments.of(data.clone(), 512, 1024),
214                 // Incremental reading
215                 Arguments.of(data.clone(), 1024, 512),
216                 // No reading
217                 Arguments.of(data.clone(), 0, 128));
218     }
219 
220     static Stream<Arguments> testToByteArray_InputStream_Size_BufferSize_Throws() {
221         return Stream.of(
222                 // Negative size
223                 Arguments.of(-1, 128, IllegalArgumentException.class),
224                 // Invalid buffer size
225                 Arguments.of(0, 0, IllegalArgumentException.class),
226                 // Truncation with requested size < chunk size
227                 Arguments.of(64, 128, EOFException.class),
228                 // Truncation with requested size > chunk size
229                 Arguments.of(Integer.MAX_VALUE, 128, EOFException.class));
230     }
231 
232     @TempDir
233     public File temporaryFolder;
234 
235     private char[] carr;
236 
237     private byte[] iarr;
238 
239     private File testFile;
240 
241     /**
242      * Path constructed from {@code testFile}.
243      */
244     private Path testFilePath;
245 
246     /** Assert that the contents of two byte arrays are the same. */
247     private void assertEqualContent(final byte[] b0, final byte[] b1) {
248         assertArrayEquals(b0, b1, "Content not equal according to java.util.Arrays#equals()");
249     }
250 
251     @BeforeEach
252     public void setUp() {
253         try {
254             testFile = new File(temporaryFolder, "file2-test.txt");
255             testFilePath = testFile.toPath();
256 
257             if (!testFile.getParentFile().exists()) {
258                 throw new IOException("Cannot create file " + testFile + " as the parent directory does not exist");
259             }
260             try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(testFilePath))) {
261                 TestUtils.generateTestData(output, FILE_SIZE);
262             }
263         } catch (final IOException e) {
264             fail("Can't run this test because the environment could not be built: " + e.getMessage());
265         }
266         // Create and init a byte array as input data
267         iarr = new byte[200];
268         Arrays.fill(iarr, (byte) -1);
269         for (int i = 0; i < 80; i++) {
270             iarr[i] = (byte) i;
271         }
272         carr = new char[200];
273         Arrays.fill(carr, (char) -1);
274         for (int i = 0; i < 80; i++) {
275             carr[i] = (char) i;
276         }
277     }
278 
279     @Test
280     void testAsBufferedInputStream() {
281         final InputStream is = new InputStream() {
282             @Override
283             public int read() throws IOException {
284                 return 0;
285             }
286         };
287         final BufferedInputStream bis = IOUtils.buffer(is);
288         assertNotSame(is, bis);
289         assertSame(bis, IOUtils.buffer(bis));
290     }
291 
292     @Test
293     void testAsBufferedInputStreamWithBufferSize() {
294         final InputStream is = new InputStream() {
295             @Override
296             public int read() throws IOException {
297                 return 0;
298             }
299         };
300         final BufferedInputStream bis = IOUtils.buffer(is, 2048);
301         assertNotSame(is, bis);
302         assertSame(bis, IOUtils.buffer(bis));
303         assertSame(bis, IOUtils.buffer(bis, 1024));
304     }
305 
306     @Test
307     void testAsBufferedNull() {
308         final String npeExpectedMessage = "Expected NullPointerException";
309         assertThrows(NullPointerException.class, () -> IOUtils.buffer((InputStream) null), npeExpectedMessage);
310         assertThrows(NullPointerException.class, () -> IOUtils.buffer((OutputStream) null), npeExpectedMessage);
311         assertThrows(NullPointerException.class, () -> IOUtils.buffer((Reader) null), npeExpectedMessage);
312         assertThrows(NullPointerException.class, () -> IOUtils.buffer((Writer) null), npeExpectedMessage);
313     }
314 
315     @Test
316     void testAsBufferedOutputStream() {
317         final OutputStream is = new OutputStream() {
318             @Override
319             public void write(final int b) throws IOException {
320             }
321         };
322         final BufferedOutputStream bis = IOUtils.buffer(is);
323         assertNotSame(is, bis);
324         assertSame(bis, IOUtils.buffer(bis));
325     }
326 
327     @Test
328     void testAsBufferedOutputStreamWithBufferSize() {
329         final OutputStream os = new OutputStream() {
330             @Override
331             public void write(final int b) throws IOException {
332             }
333         };
334         final BufferedOutputStream bos = IOUtils.buffer(os, 2048);
335         assertNotSame(os, bos);
336         assertSame(bos, IOUtils.buffer(bos));
337         assertSame(bos, IOUtils.buffer(bos, 1024));
338     }
339 
340     @Test
341     void testAsBufferedReader() {
342         final Reader is = new Reader() {
343             @Override
344             public void close() throws IOException {
345             }
346 
347             @Override
348             public int read(final char[] cbuf, final int off, final int len) throws IOException {
349                 return 0;
350             }
351         };
352         final BufferedReader bis = IOUtils.buffer(is);
353         assertNotSame(is, bis);
354         assertSame(bis, IOUtils.buffer(bis));
355     }
356 
357     @Test
358     void testAsBufferedReaderWithBufferSize() {
359         final Reader r = new Reader() {
360             @Override
361             public void close() throws IOException {
362             }
363 
364             @Override
365             public int read(final char[] cbuf, final int off, final int len) throws IOException {
366                 return 0;
367             }
368         };
369         final BufferedReader br = IOUtils.buffer(r, 2048);
370         assertNotSame(r, br);
371         assertSame(br, IOUtils.buffer(br));
372         assertSame(br, IOUtils.buffer(br, 1024));
373     }
374 
375     @Test
376     void testAsBufferedWriter() {
377         final Writer nullWriter = NullWriter.INSTANCE;
378         final BufferedWriter bis = IOUtils.buffer(nullWriter);
379         assertNotSame(nullWriter, bis);
380         assertSame(bis, IOUtils.buffer(bis));
381     }
382 
383     @Test
384     void testAsBufferedWriterWithBufferSize() {
385         final Writer nullWriter = NullWriter.INSTANCE;
386         final BufferedWriter bw = IOUtils.buffer(nullWriter, 2024);
387         assertNotSame(nullWriter, bw);
388         assertSame(bw, IOUtils.buffer(bw));
389         assertSame(bw, IOUtils.buffer(bw, 1024));
390     }
391 
392     @Test
393     void testAsWriterAppendable() throws IOException {
394         final Appendable a = new StringBuffer();
395         try (Writer w = IOUtils.writer(a)) {
396             assertNotSame(w, a);
397             assertEquals(AppendableWriter.class, w.getClass());
398             assertSame(w, IOUtils.writer(w));
399         }
400     }
401 
402     @Test
403     void testAsWriterNull() {
404         assertThrows(NullPointerException.class, () -> IOUtils.writer(null));
405     }
406 
407     @Test
408     void testAsWriterStringBuilder() throws IOException {
409         final Appendable a = new StringBuilder();
410         try (Writer w = IOUtils.writer(a)) {
411             assertNotSame(w, a);
412             assertEquals(StringBuilderWriter.class, w.getClass());
413             assertSame(w, IOUtils.writer(w));
414         }
415     }
416 
417     @Test
418     void testByteArrayWithNegativeSize() {
419         assertThrows(NegativeArraySizeException.class, () -> IOUtils.byteArray(-1));
420     }
421 
422     @ParameterizedTest
423     @MethodSource
424     void testCheckFromIndexSizeInvalidCases(final int off, final int len, final int arrayLength) {
425         final IndexOutOfBoundsException ex = assertThrows(IndexOutOfBoundsException.class, () -> IOUtils.checkFromIndexSize(off, len, arrayLength));
426         assertTrue(ex.getMessage().contains(String.valueOf(off)));
427         assertTrue(ex.getMessage().contains(String.valueOf(len)));
428         assertTrue(ex.getMessage().contains(String.valueOf(arrayLength)));
429         // Optional requirement: compare the exception message for Java 8 and Java 9+
430         if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9)) {
431             final IndexOutOfBoundsException jreEx = assertThrows(IndexOutOfBoundsException.class, () -> {
432                 try {
433                     Objects.class.getDeclaredMethod("checkFromIndexSize", int.class, int.class, int.class).invoke(null, off, len, arrayLength);
434                 } catch (final InvocationTargetException ite) {
435                     throw ite.getTargetException();
436                 }
437             });
438             assertEquals(jreEx.getMessage(), ex.getMessage());
439         }
440     }
441 
442     @ParameterizedTest
443     @MethodSource
444     void testCheckFromIndexSizeValidCases(final int off, final int len, final int arrayLength) {
445         assertDoesNotThrow(() -> IOUtils.checkFromIndexSize(off, len, arrayLength));
446     }
447 
448     @ParameterizedTest
449     @MethodSource
450     void testCheckFromToIndexInvalidCases(final int from, final int to, final int arrayLength) {
451         final IndexOutOfBoundsException ex = assertThrows(IndexOutOfBoundsException.class, () -> IOUtils.checkFromToIndex(from, to, arrayLength));
452         assertTrue(ex.getMessage().contains(String.valueOf(from)));
453         assertTrue(ex.getMessage().contains(String.valueOf(to)));
454         assertTrue(ex.getMessage().contains(String.valueOf(arrayLength)));
455         // Optional requirement: compare the exception message for Java 8 and Java 9+
456         if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9)) {
457             final IndexOutOfBoundsException jreEx = assertThrows(IndexOutOfBoundsException.class, () -> {
458                 try {
459                     Objects.class.getDeclaredMethod("checkFromToIndex", int.class, int.class, int.class).invoke(null, from, to, arrayLength);
460                 } catch (final InvocationTargetException ite) {
461                     throw ite.getTargetException();
462                 }
463             });
464             assertEquals(jreEx.getMessage(), ex.getMessage());
465         }
466     }
467 
468     @ParameterizedTest
469     @MethodSource
470     void testCheckFromToIndexValidCases(final int from, final int to, final int arrayLength) {
471         assertDoesNotThrow(() -> IOUtils.checkFromToIndex(from, to, arrayLength));
472     }
473 
474     @Test
475     void testClose() {
476         assertDoesNotThrow(() -> IOUtils.close((Closeable) null));
477         assertDoesNotThrow(() -> IOUtils.close(new StringReader("s")));
478         assertThrows(IOException.class, () -> IOUtils.close(new ThrowOnCloseReader(new StringReader("s"))));
479     }
480 
481     @Test
482     void testCloseConsumer() {
483         // null consumer
484         final Closeable nullCloseable = null;
485         assertDoesNotThrow(() -> IOUtils.close(nullCloseable, null));
486         assertDoesNotThrow(() -> IOUtils.close(new StringReader("s"), null));
487         assertDoesNotThrow(() -> IOUtils.close(new ThrowOnCloseReader(new StringReader("s")), null));
488         // null consumer doesn't throw
489         final IOConsumer<IOException> nullConsumer = null;
490         assertDoesNotThrow(() -> IOUtils.close(nullCloseable, nullConsumer));
491         assertDoesNotThrow(() -> IOUtils.close(new StringReader("s"), nullConsumer));
492         assertDoesNotThrow(() -> IOUtils.close(new ThrowOnCloseReader(new StringReader("s")), nullConsumer));
493         // noop consumer doesn't throw
494         final IOConsumer<IOException> silentConsumer = IOConsumer.noop();
495         assertDoesNotThrow(() -> IOUtils.close(nullCloseable, silentConsumer));
496         assertDoesNotThrow(() -> IOUtils.close(new StringReader("s"), silentConsumer));
497         assertDoesNotThrow(() -> IOUtils.close(new ThrowOnCloseReader(new StringReader("s")), silentConsumer));
498         // consumer passes on the throw
499         final IOConsumer<IOException> noisyConsumer = ExceptionUtils::rethrow;
500         // no throw
501         assertDoesNotThrow(() -> IOUtils.close(nullCloseable, noisyConsumer));
502         // no throw
503         assertDoesNotThrow(() -> IOUtils.close(new StringReader("s"), noisyConsumer));
504         // closeable throws
505         assertThrows(IOException.class, () -> IOUtils.close(new ThrowOnCloseReader(new StringReader("s")), noisyConsumer));
506         // consumes other than IOException
507         final AtomicBoolean b = new AtomicBoolean();
508         final IOConsumer<IOException> consumer = e -> b.set(true);
509         // IOException subclass
510         assertDoesNotThrow(() -> IOUtils.close(new BrokenOutputStream((Throwable) new EOFException()), consumer));
511         assertTrue(b.get());
512         b.set(false);
513         // RuntimeException
514         assertDoesNotThrow(() -> IOUtils.close(new BrokenOutputStream(new RuntimeException()), consumer));
515         assertTrue(b.get());
516         b.set(false);
517         // RuntimeException subclass
518         assertDoesNotThrow(() -> IOUtils.close(new BrokenOutputStream(new UnsupportedOperationException()), consumer));
519         assertTrue(b.get());
520     }
521 
522     @Test
523     void testCloseMulti() {
524         final Closeable nullCloseable = null;
525         final Closeable[] closeables = {null, null};
526         assertDoesNotThrow(() -> IOUtils.close(nullCloseable, nullCloseable));
527         assertDoesNotThrow(() -> IOUtils.close(closeables));
528         assertDoesNotThrow(() -> IOUtils.close((Closeable[]) null));
529         assertDoesNotThrow(() -> IOUtils.close(new StringReader("s"), nullCloseable));
530         assertThrows(IOException.class, () -> IOUtils.close(nullCloseable, new ThrowOnCloseReader(new StringReader("s"))));
531     }
532 
533     @Test
534     void testCloseQuietly_AllCloseableIOException() {
535         final Closeable closeable = BrokenInputStream.INSTANCE;
536         assertDoesNotThrow(() -> IOUtils.closeQuietly(closeable, null, closeable));
537         assertDoesNotThrow(() -> IOUtils.closeQuietly(Arrays.asList(closeable, null, closeable)));
538         assertDoesNotThrow(() -> IOUtils.closeQuietly(Stream.of(closeable, null, closeable)));
539         assertDoesNotThrow(() -> IOUtils.closeQuietly((Iterable<Closeable>) null));
540     }
541 
542     @Test
543     void testCloseQuietly_CloseableException() {
544         // IOException
545         assertDoesNotThrow(() -> IOUtils.closeQuietly(BrokenInputStream.INSTANCE));
546         assertDoesNotThrow(() -> IOUtils.closeQuietly(BrokenOutputStream.INSTANCE));
547         // IOException subclass
548         assertDoesNotThrow(() -> IOUtils.closeQuietly(new BrokenOutputStream((Throwable) new EOFException())));
549         // RuntimeException
550         assertDoesNotThrow(() -> IOUtils.closeQuietly(new BrokenOutputStream(new RuntimeException())));
551         // RuntimeException subclass
552         assertDoesNotThrow(() -> IOUtils.closeQuietly(new BrokenOutputStream(new UnsupportedOperationException())));
553     }
554 
555     @Test
556     void testCloseQuietly_CloseableExceptionConsumer() {
557         final AtomicBoolean b = new AtomicBoolean();
558         final Consumer<Exception> consumer = e -> b.set(true);
559         // IOException
560         assertDoesNotThrow(() -> IOUtils.closeQuietly(BrokenInputStream.INSTANCE, consumer));
561         assertTrue(b.get());
562         b.set(false);
563         assertDoesNotThrow(() -> IOUtils.closeQuietly(BrokenOutputStream.INSTANCE, consumer));
564         assertTrue(b.get());
565         b.set(false);
566         // IOException subclass
567         assertDoesNotThrow(() -> IOUtils.closeQuietly(new BrokenOutputStream((Throwable) new EOFException()), consumer));
568         assertTrue(b.get());
569         b.set(false);
570         // RuntimeException
571         assertDoesNotThrow(() -> IOUtils.closeQuietly(new BrokenOutputStream(new RuntimeException()), consumer));
572         assertTrue(b.get());
573         b.set(false);
574         // RuntimeException subclass
575         assertDoesNotThrow(() -> IOUtils.closeQuietly(new BrokenOutputStream(new UnsupportedOperationException()), consumer));
576         assertTrue(b.get());
577     }
578 
579     @SuppressWarnings("squid:S2699") // Suppress "Add at least one assertion to this test case"
580     @Test
581     void testCloseQuietly_Selector() {
582         Selector selector = null;
583         try {
584             selector = Selector.open();
585         } catch (final IOException ignore) {
586         } finally {
587             IOUtils.closeQuietly(selector);
588         }
589     }
590 
591     @SuppressWarnings("squid:S2699") // Suppress "Add at least one assertion to this test case"
592     @Test
593     void testCloseQuietly_SelectorIOException() {
594         final Selector selector = new SelectorAdapter() {
595             @Override
596             public void close() throws IOException {
597                 throw new IOException();
598             }
599         };
600         IOUtils.closeQuietly(selector);
601     }
602 
603     @SuppressWarnings("squid:S2699") // Suppress "Add at least one assertion to this test case"
604     @Test
605     void testCloseQuietly_SelectorNull() {
606         final Selector selector = null;
607         IOUtils.closeQuietly(selector);
608     }
609 
610     @SuppressWarnings("squid:S2699") // Suppress "Add at least one assertion to this test case"
611     @Test
612     void testCloseQuietly_SelectorTwice() {
613         Selector selector = null;
614         try {
615             selector = Selector.open();
616         } catch (final IOException ignore) {
617         } finally {
618             IOUtils.closeQuietly(selector);
619             IOUtils.closeQuietly(selector);
620         }
621     }
622 
623     @Test
624     void testCloseQuietly_ServerSocket() {
625         assertDoesNotThrow(() -> IOUtils.closeQuietly((ServerSocket) null));
626         assertDoesNotThrow(() -> IOUtils.closeQuietly(new ServerSocket()));
627     }
628 
629     @Test
630     void testCloseQuietly_ServerSocketIOException() {
631         assertDoesNotThrow(() -> {
632             IOUtils.closeQuietly(new ServerSocket() {
633                 @Override
634                 public void close() throws IOException {
635                     throw new IOException();
636                 }
637             });
638         });
639     }
640 
641     @Test
642     void testCloseQuietly_Socket() {
643         assertDoesNotThrow(() -> IOUtils.closeQuietly((Socket) null));
644         assertDoesNotThrow(() -> IOUtils.closeQuietly(new Socket()));
645     }
646 
647     @Test
648     void testCloseQuietly_SocketIOException() {
649         assertDoesNotThrow(() -> {
650             IOUtils.closeQuietly(new Socket() {
651                 @Override
652                 public synchronized void close() throws IOException {
653                     throw new IOException();
654                 }
655             });
656         });
657     }
658 
659     @Test
660     void testCloseURLConnection() {
661         assertDoesNotThrow(() -> IOUtils.close((URLConnection) null));
662         assertDoesNotThrow(() -> IOUtils.close(new URL("https://www.apache.org/").openConnection()));
663         assertDoesNotThrow(() -> IOUtils.close(new URL("file:///").openConnection()));
664     }
665 
666     @Test
667     void testConstants() {
668         assertEquals('/', IOUtils.DIR_SEPARATOR_UNIX);
669         assertEquals('\\', IOUtils.DIR_SEPARATOR_WINDOWS);
670         assertEquals("\n", IOUtils.LINE_SEPARATOR_UNIX);
671         assertEquals("\r\n", IOUtils.LINE_SEPARATOR_WINDOWS);
672         if (WINDOWS) {
673             assertEquals('\\', IOUtils.DIR_SEPARATOR);
674             assertEquals("\r\n", IOUtils.LINE_SEPARATOR);
675         } else {
676             assertEquals('/', IOUtils.DIR_SEPARATOR);
677             assertEquals("\n", IOUtils.LINE_SEPARATOR);
678         }
679         assertEquals('\r', IOUtils.CR);
680         assertEquals('\n', IOUtils.LF);
681         assertEquals(-1, IOUtils.EOF);
682     }
683 
684     @Test
685     void testConsumeInputStream() throws Exception {
686         final long size = (long) Integer.MAX_VALUE + (long) 1;
687         final NullInputStream in = new NullInputStream(size);
688         final OutputStream out = NullOutputStream.INSTANCE;
689 
690         // Test copy() method
691         assertEquals(-1, IOUtils.copy(in, out));
692 
693         // reset the input
694         in.init();
695 
696         // Test consume() method
697         assertEquals(size, IOUtils.consume(in), "consume()");
698     }
699 
700     @Test
701     void testConsumeReader() throws Exception {
702         final long size = (long) Integer.MAX_VALUE + (long) 1;
703         final Reader in = new NullReader(size);
704         final Writer out = NullWriter.INSTANCE;
705         // Test copy() method
706         assertEquals(-1, IOUtils.copy(in, out));
707         // reset the input
708         in.close();
709         // Test consume() method
710         assertEquals(size, IOUtils.consume(in), "consume()");
711     }
712 
713     @Test
714     void testContentEquals_InputStream_InputStream() throws Exception {
715         {
716             assertTrue(IOUtils.contentEquals((InputStream) null, null));
717         }
718         final byte[] dataEmpty = "".getBytes(StandardCharsets.UTF_8);
719         final byte[] dataAbc = "ABC".getBytes(StandardCharsets.UTF_8);
720         final byte[] dataAbcd = "ABCD".getBytes(StandardCharsets.UTF_8);
721         {
722             final ByteArrayInputStream input1 = new ByteArrayInputStream(dataEmpty);
723             assertFalse(IOUtils.contentEquals(input1, null));
724         }
725         {
726             final ByteArrayInputStream input1 = new ByteArrayInputStream(dataEmpty);
727             assertFalse(IOUtils.contentEquals(null, input1));
728         }
729         {
730             final ByteArrayInputStream input1 = new ByteArrayInputStream(dataEmpty);
731             assertTrue(IOUtils.contentEquals(input1, input1));
732         }
733         {
734             final ByteArrayInputStream input1 = new ByteArrayInputStream(dataAbc);
735             assertTrue(IOUtils.contentEquals(input1, input1));
736         }
737         assertTrue(IOUtils.contentEquals(new ByteArrayInputStream(dataEmpty), new ByteArrayInputStream(dataEmpty)));
738         assertTrue(IOUtils.contentEquals(new BufferedInputStream(new ByteArrayInputStream(dataEmpty)),
739             new BufferedInputStream(new ByteArrayInputStream(dataEmpty))));
740         assertTrue(IOUtils.contentEquals(new ByteArrayInputStream(dataAbc), new ByteArrayInputStream(dataAbc)));
741         assertFalse(IOUtils.contentEquals(new ByteArrayInputStream(dataAbcd), new ByteArrayInputStream(dataAbc)));
742         assertFalse(IOUtils.contentEquals(new ByteArrayInputStream(dataAbc), new ByteArrayInputStream(dataAbcd)));
743         assertFalse(IOUtils.contentEquals(new ByteArrayInputStream("apache".getBytes(StandardCharsets.UTF_8)),
744                 new ByteArrayInputStream("apacha".getBytes(StandardCharsets.UTF_8))));
745         // Tests with larger inputs that DEFAULT_BUFFER_SIZE in case internal buffers are used.
746         final byte[] bytes2XDefaultA = new byte[IOUtils.DEFAULT_BUFFER_SIZE * 2];
747         final byte[] bytes2XDefaultB = new byte[IOUtils.DEFAULT_BUFFER_SIZE * 2];
748         final byte[] bytes2XDefaultA2 = new byte[IOUtils.DEFAULT_BUFFER_SIZE * 2];
749         Arrays.fill(bytes2XDefaultA, (byte) 'a');
750         Arrays.fill(bytes2XDefaultB, (byte) 'b');
751         Arrays.fill(bytes2XDefaultA2, (byte) 'a');
752         bytes2XDefaultA2[bytes2XDefaultA2.length - 1] = 'd';
753         assertFalse(IOUtils.contentEquals(new ByteArrayInputStream(bytes2XDefaultA),
754             new ByteArrayInputStream(bytes2XDefaultB)));
755         assertFalse(IOUtils.contentEquals(new ByteArrayInputStream(bytes2XDefaultA),
756             new ByteArrayInputStream(bytes2XDefaultA2)));
757         assertTrue(IOUtils.contentEquals(new ByteArrayInputStream(bytes2XDefaultA),
758             new ByteArrayInputStream(bytes2XDefaultA)));
759         // FileInputStream a bit more than 16 k.
760         try (
761             FileInputStream input1 = new FileInputStream(
762                 "src/test/resources/org/apache/commons/io/abitmorethan16k.txt");
763             FileInputStream input2 = new FileInputStream(
764                 "src/test/resources/org/apache/commons/io/abitmorethan16kcopy.txt")) {
765             assertTrue(IOUtils.contentEquals(input1, input1));
766         }
767     }
768 
769     @Test
770     void testContentEquals_Reader_Reader() throws Exception {
771         {
772             assertTrue(IOUtils.contentEquals((Reader) null, null));
773         }
774         {
775             final StringReader input1 = new StringReader("");
776             assertFalse(IOUtils.contentEquals(null, input1));
777         }
778         {
779             final StringReader input1 = new StringReader("");
780             assertFalse(IOUtils.contentEquals(input1, null));
781         }
782         {
783             final StringReader input1 = new StringReader("");
784             assertTrue(IOUtils.contentEquals(input1, input1));
785         }
786         {
787             final StringReader input1 = new StringReader("ABC");
788             assertTrue(IOUtils.contentEquals(input1, input1));
789         }
790         assertTrue(IOUtils.contentEquals(new StringReader(""), new StringReader("")));
791         assertTrue(
792             IOUtils.contentEquals(new BufferedReader(new StringReader("")), new BufferedReader(new StringReader(""))));
793         assertTrue(IOUtils.contentEquals(new StringReader("ABC"), new StringReader("ABC")));
794         assertFalse(IOUtils.contentEquals(new StringReader("ABCD"), new StringReader("ABC")));
795         assertFalse(IOUtils.contentEquals(new StringReader("ABC"), new StringReader("ABCD")));
796         assertFalse(IOUtils.contentEquals(new StringReader("apache"), new StringReader("apacha")));
797     }
798 
799     @Test
800     void testContentEqualsIgnoreEOL() throws Exception {
801         {
802             assertTrue(IOUtils.contentEqualsIgnoreEOL(null, null));
803         }
804         final char[] empty = {};
805         {
806             final Reader input1 = new CharArrayReader(empty);
807             assertFalse(IOUtils.contentEqualsIgnoreEOL(null, input1));
808         }
809         {
810             final Reader input1 = new CharArrayReader(empty);
811             assertFalse(IOUtils.contentEqualsIgnoreEOL(input1, null));
812         }
813         {
814             final Reader input1 = new CharArrayReader(empty);
815             assertTrue(IOUtils.contentEqualsIgnoreEOL(input1, input1));
816         }
817         {
818             final Reader input1 = new CharArrayReader("321\r\n".toCharArray());
819             assertTrue(IOUtils.contentEqualsIgnoreEOL(input1, input1));
820         }
821 
822         testSingleEOL("", "", true);
823         testSingleEOL("", "\n", false);
824         testSingleEOL("", "\r", false);
825         testSingleEOL("", "\r\n", false);
826         testSingleEOL("", "\r\r", false);
827         testSingleEOL("", "\n\n", false);
828         testSingleEOL("1", "1", true);
829         testSingleEOL("1", "2", false);
830         testSingleEOL("123\rabc", "123\nabc", true);
831         testSingleEOL("321", "321\r\n", true);
832         testSingleEOL("321", "321\r\naabb", false);
833         testSingleEOL("321", "321\n", true);
834         testSingleEOL("321", "321\r", true);
835         testSingleEOL("321", "321\r\n", true);
836         testSingleEOL("321", "321\r\r", false);
837         testSingleEOL("321", "321\n\r", false);
838         testSingleEOL("321\n", "321", true);
839         testSingleEOL("321\n", "321\n\r", false);
840         testSingleEOL("321\n", "321\r\n", true);
841         testSingleEOL("321\r", "321\r\n", true);
842         testSingleEOL("321\r\n", "321\r\n\r", false);
843         testSingleEOL("123", "1234", false);
844         testSingleEOL("1235", "1234", false);
845     }
846 
847     @Test
848     void testContentEqualsSequenceInputStream() throws Exception {
849         // https://issues.apache.org/jira/browse/IO-866
850         // not equals
851         // @formatter:off
852         assertFalse(IOUtils.contentEquals(
853                 new ByteArrayInputStream("ab".getBytes()),
854                 new SequenceInputStream(
855                     new ByteArrayInputStream("a".getBytes()),
856                     new ByteArrayInputStream("b-".getBytes()))));
857         assertFalse(IOUtils.contentEquals(
858                 new ByteArrayInputStream("ab".getBytes()),
859                 new SequenceInputStream(
860                     new ByteArrayInputStream("a-".getBytes()),
861                     new ByteArrayInputStream("b".getBytes()))));
862         assertFalse(IOUtils.contentEquals(
863                 new ByteArrayInputStream("ab-".getBytes()),
864                 new SequenceInputStream(
865                     new ByteArrayInputStream("a".getBytes()),
866                     new ByteArrayInputStream("b".getBytes()))));
867         assertFalse(IOUtils.contentEquals(
868                 new ByteArrayInputStream("".getBytes()),
869                 new SequenceInputStream(
870                     new ByteArrayInputStream("a".getBytes()),
871                     new ByteArrayInputStream("b".getBytes()))));
872         assertFalse(IOUtils.contentEquals(
873                 new ByteArrayInputStream("".getBytes()),
874                 new SequenceInputStream(
875                     new ByteArrayInputStream("".getBytes()),
876                     new ByteArrayInputStream("b".getBytes()))));
877         assertFalse(IOUtils.contentEquals(
878                 new ByteArrayInputStream("ab".getBytes()),
879                 new SequenceInputStream(
880                     new ByteArrayInputStream("".getBytes()),
881                     new ByteArrayInputStream("".getBytes()))));
882         // equals
883         assertTrue(IOUtils.contentEquals(
884                 new ByteArrayInputStream("".getBytes()),
885                 new SequenceInputStream(
886                     new ByteArrayInputStream("".getBytes()),
887                     new ByteArrayInputStream("".getBytes()))));
888         assertTrue(IOUtils.contentEquals(
889                 new ByteArrayInputStream("ab".getBytes()),
890                 new SequenceInputStream(
891                     new ByteArrayInputStream("a".getBytes()),
892                     new ByteArrayInputStream("b".getBytes()))));
893         assertTrue(IOUtils.contentEquals(
894                 new ByteArrayInputStream("ab".getBytes()),
895                 new SequenceInputStream(
896                     new ByteArrayInputStream("ab".getBytes()),
897                     new ByteArrayInputStream("".getBytes()))));
898         assertTrue(IOUtils.contentEquals(
899                 new ByteArrayInputStream("ab".getBytes()),
900                 new SequenceInputStream(
901                     new ByteArrayInputStream("".getBytes()),
902                     new ByteArrayInputStream("ab".getBytes()))));
903         // @formatter:on
904         final byte[] prefixLen32 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 };
905         final byte[] suffixLen2 = { 1, 2 };
906         final byte[] fileContents = "someTexts".getBytes(StandardCharsets.UTF_8);
907         Files.write(testFile.toPath(), fileContents);
908         final byte[] expected = new byte[prefixLen32.length + fileContents.length + suffixLen2.length];
909         System.arraycopy(prefixLen32, 0, expected, 0, prefixLen32.length);
910         System.arraycopy(fileContents, 0, expected, prefixLen32.length, fileContents.length);
911         System.arraycopy(suffixLen2, 0, expected, prefixLen32.length + fileContents.length, suffixLen2.length);
912         // @formatter:off
913         assertTrue(IOUtils.contentEquals(
914                 new ByteArrayInputStream(expected),
915                 new SequenceInputStream(
916                     Collections.enumeration(
917                         Arrays.asList(
918                             new ByteArrayInputStream(prefixLen32),
919                             new FileInputStream(testFile),
920                             new ByteArrayInputStream(suffixLen2))))));
921         // @formatter:on
922     }
923 
924     @Test
925     void testCopy_ByteArray_OutputStream() throws Exception {
926         final File destination = TestUtils.newFile(temporaryFolder, "copy8.txt");
927         final byte[] in;
928         try (InputStream fin = Files.newInputStream(testFilePath)) {
929             // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
930             in = IOUtils.toByteArray(fin);
931         }
932         try (OutputStream fout = Files.newOutputStream(destination.toPath())) {
933             CopyUtils.copy(in, fout);
934             fout.flush();
935             TestUtils.checkFile(destination, testFile);
936             TestUtils.checkWrite(fout);
937         }
938         TestUtils.deleteFile(destination);
939     }
940 
941     @Test
942     void testCopy_ByteArray_Writer() throws Exception {
943         final File destination = TestUtils.newFile(temporaryFolder, "copy7.txt");
944         final byte[] in;
945         try (InputStream fin = Files.newInputStream(testFilePath)) {
946             // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
947             in = IOUtils.toByteArray(fin);
948         }
949         try (Writer fout = Files.newBufferedWriter(destination.toPath())) {
950             CopyUtils.copy(in, fout);
951             fout.flush();
952             TestUtils.checkFile(destination, testFile);
953             TestUtils.checkWrite(fout);
954         }
955         TestUtils.deleteFile(destination);
956     }
957 
958     @Test
959     void testCopy_String_Writer() throws Exception {
960         final File destination = TestUtils.newFile(temporaryFolder, "copy6.txt");
961         final String str;
962         try (Reader fin = Files.newBufferedReader(testFilePath)) {
963             // Create our String. Rely on testReaderToString() to make sure this is valid.
964             str = IOUtils.toString(fin);
965         }
966         try (Writer fout = Files.newBufferedWriter(destination.toPath())) {
967             CopyUtils.copy(str, fout);
968             fout.flush();
969             TestUtils.checkFile(destination, testFile);
970             TestUtils.checkWrite(fout);
971         }
972         TestUtils.deleteFile(destination);
973     }
974 
975     @Test
976     void testCopyLarge_CharExtraLength() throws IOException {
977         CharArrayReader is = null;
978         CharArrayWriter os = null;
979         try {
980             // Create streams
981             is = new CharArrayReader(carr);
982             os = new CharArrayWriter();
983             // Test our copy method
984             // for extra length, it reads till EOF
985             assertEquals(200, IOUtils.copyLarge(is, os, 0, 2000));
986             final char[] oarr = os.toCharArray();
987             // check that output length is correct
988             assertEquals(200, oarr.length);
989             // check that output data corresponds to input data
990             assertEquals(1, oarr[1]);
991             assertEquals(79, oarr[79]);
992             assertEquals((char) -1, oarr[80]);
993         } finally {
994             IOUtils.closeQuietly(is);
995             IOUtils.closeQuietly(os);
996         }
997     }
998 
999     @Test
1000     void testCopyLarge_CharFullLength() throws IOException {
1001         CharArrayReader is = null;
1002         CharArrayWriter os = null;
1003         try {
1004             // Create streams
1005             is = new CharArrayReader(carr);
1006             os = new CharArrayWriter();
1007             // Test our copy method
1008             assertEquals(200, IOUtils.copyLarge(is, os, 0, -1));
1009             final char[] oarr = os.toCharArray();
1010             // check that output length is correct
1011             assertEquals(200, oarr.length);
1012             // check that output data corresponds to input data
1013             assertEquals(1, oarr[1]);
1014             assertEquals(79, oarr[79]);
1015             assertEquals((char) -1, oarr[80]);
1016         } finally {
1017             IOUtils.closeQuietly(is);
1018             IOUtils.closeQuietly(os);
1019         }
1020     }
1021 
1022     @Test
1023     void testCopyLarge_CharNoSkip() throws IOException {
1024         CharArrayReader is = null;
1025         CharArrayWriter os = null;
1026         try {
1027             // Create streams
1028             is = new CharArrayReader(carr);
1029             os = new CharArrayWriter();
1030             // Test our copy method
1031             assertEquals(100, IOUtils.copyLarge(is, os, 0, 100));
1032             final char[] oarr = os.toCharArray();
1033             // check that output length is correct
1034             assertEquals(100, oarr.length);
1035             // check that output data corresponds to input data
1036             assertEquals(1, oarr[1]);
1037             assertEquals(79, oarr[79]);
1038             assertEquals((char) -1, oarr[80]);
1039         } finally {
1040             IOUtils.closeQuietly(is);
1041             IOUtils.closeQuietly(os);
1042         }
1043     }
1044 
1045     @Test
1046     void testCopyLarge_CharSkip() throws IOException {
1047         CharArrayReader is = null;
1048         CharArrayWriter os = null;
1049         try {
1050             // Create streams
1051             is = new CharArrayReader(carr);
1052             os = new CharArrayWriter();
1053             // Test our copy method
1054             assertEquals(100, IOUtils.copyLarge(is, os, 10, 100));
1055             final char[] oarr = os.toCharArray();
1056             // check that output length is correct
1057             assertEquals(100, oarr.length);
1058             // check that output data corresponds to input data
1059             assertEquals(11, oarr[1]);
1060             assertEquals(79, oarr[69]);
1061             assertEquals((char) -1, oarr[70]);
1062         } finally {
1063             IOUtils.closeQuietly(is);
1064             IOUtils.closeQuietly(os);
1065         }
1066     }
1067 
1068     @Test
1069     void testCopyLarge_CharSkipInvalid() {
1070         try (CharArrayReader is = new CharArrayReader(carr); CharArrayWriter os = new CharArrayWriter()) {
1071             assertThrows(EOFException.class, () -> IOUtils.copyLarge(is, os, 1000, 100));
1072         }
1073     }
1074 
1075     @Test
1076     void testCopyLarge_ExtraLength() throws IOException {
1077         try (ByteArrayInputStream is = new ByteArrayInputStream(iarr); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
1078             // Create streams
1079             // Test our copy method
1080             // for extra length, it reads till EOF
1081             assertEquals(200, IOUtils.copyLarge(is, os, 0, 2000));
1082             final byte[] oarr = os.toByteArray();
1083             // check that output length is correct
1084             assertEquals(200, oarr.length);
1085             // check that output data corresponds to input data
1086             assertEquals(1, oarr[1]);
1087             assertEquals(79, oarr[79]);
1088             assertEquals(-1, oarr[80]);
1089         }
1090     }
1091 
1092     @Test
1093     void testCopyLarge_FullLength() throws IOException {
1094         try (ByteArrayInputStream is = new ByteArrayInputStream(iarr); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
1095             // Test our copy method
1096             assertEquals(200, IOUtils.copyLarge(is, os, 0, -1));
1097             final byte[] oarr = os.toByteArray();
1098             // check that output length is correct
1099             assertEquals(200, oarr.length);
1100             // check that output data corresponds to input data
1101             assertEquals(1, oarr[1]);
1102             assertEquals(79, oarr[79]);
1103             assertEquals(-1, oarr[80]);
1104         }
1105     }
1106 
1107     @Test
1108     void testCopyLarge_NoSkip() throws IOException {
1109         try (ByteArrayInputStream is = new ByteArrayInputStream(iarr); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
1110             // Test our copy method
1111             assertEquals(100, IOUtils.copyLarge(is, os, 0, 100));
1112             final byte[] oarr = os.toByteArray();
1113             // check that output length is correct
1114             assertEquals(100, oarr.length);
1115             // check that output data corresponds to input data
1116             assertEquals(1, oarr[1]);
1117             assertEquals(79, oarr[79]);
1118             assertEquals(-1, oarr[80]);
1119         }
1120     }
1121 
1122     @Test
1123     void testCopyLarge_Skip() throws IOException {
1124         try (ByteArrayInputStream is = new ByteArrayInputStream(iarr); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
1125             // Test our copy method
1126             assertEquals(100, IOUtils.copyLarge(is, os, 10, 100));
1127             final byte[] oarr = os.toByteArray();
1128             // check that output length is correct
1129             assertEquals(100, oarr.length);
1130             // check that output data corresponds to input data
1131             assertEquals(11, oarr[1]);
1132             assertEquals(79, oarr[69]);
1133             assertEquals(-1, oarr[70]);
1134         }
1135     }
1136 
1137     @Test
1138     void testCopyLarge_SkipInvalid() throws IOException {
1139         try (ByteArrayInputStream is = new ByteArrayInputStream(iarr);
1140             ByteArrayOutputStream os = new ByteArrayOutputStream()) {
1141             // Test our copy method
1142             assertThrows(EOFException.class, () -> IOUtils.copyLarge(is, os, 1000, 100));
1143         }
1144     }
1145 
1146     @Test
1147     void testCopyLarge_SkipWithInvalidOffset() throws IOException {
1148         ByteArrayInputStream is = null;
1149         ByteArrayOutputStream os = null;
1150         try {
1151             // Create streams
1152             is = new ByteArrayInputStream(iarr);
1153             os = new ByteArrayOutputStream();
1154             // Test our copy method
1155             assertEquals(100, IOUtils.copyLarge(is, os, -10, 100));
1156             final byte[] oarr = os.toByteArray();
1157             // check that output length is correct
1158             assertEquals(100, oarr.length);
1159             // check that output data corresponds to input data
1160             assertEquals(1, oarr[1]);
1161             assertEquals(79, oarr[79]);
1162             assertEquals(-1, oarr[80]);
1163         } finally {
1164             IOUtils.closeQuietly(is);
1165             IOUtils.closeQuietly(os);
1166         }
1167     }
1168 
1169     @ParameterizedTest
1170     @MethodSource("invalidRead_InputStream_Offset_ArgumentsProvider")
1171     void testRead_InputStream_Offset_ArgumentsValidation(final InputStream input, final byte[] b, final int off, final int len,
1172             final Class<? extends Throwable> expected) {
1173         assertThrows(expected, () -> IOUtils.read(input, b, off, len));
1174     }
1175 
1176     @Test
1177     void testRead_ReadableByteChannel() throws Exception {
1178         final ByteBuffer buffer = ByteBuffer.allocate(FILE_SIZE);
1179         final FileInputStream fileInputStream = new FileInputStream(testFile);
1180         final FileChannel input = fileInputStream.getChannel();
1181         try {
1182             assertEquals(FILE_SIZE, IOUtils.read(input, buffer));
1183             assertEquals(0, IOUtils.read(input, buffer));
1184             assertEquals(0, buffer.remaining());
1185             assertEquals(0, input.read(buffer));
1186             buffer.clear();
1187             assertThrows(EOFException.class, () -> IOUtils.readFully(input, buffer));
1188         } finally {
1189             IOUtils.closeQuietly(input, fileInputStream);
1190         }
1191     }
1192 
1193     @Test
1194     void testReadFully_InputStream__ReturnByteArray() throws Exception {
1195         final byte[] bytes = "abcd1234".getBytes(StandardCharsets.UTF_8);
1196         final ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
1197         final byte[] result = IOUtils.readFully(stream, bytes.length);
1198         IOUtils.closeQuietly(stream);
1199         assertEqualContent(result, bytes);
1200     }
1201 
1202     @Test
1203     void testReadFully_InputStream_ByteArray() throws Exception {
1204         final int size = 1027;
1205         final byte[] buffer = new byte[size];
1206         final InputStream input = new ByteArrayInputStream(new byte[size]);
1207 
1208         assertThrows(IndexOutOfBoundsException.class, () -> IOUtils.readFully(input, buffer, 0, -1));
1209 
1210         IOUtils.readFully(input, buffer, 0, 0);
1211         IOUtils.readFully(input, buffer, 0, size - 1);
1212         assertThrows(EOFException.class, () -> IOUtils.readFully(input, buffer, 0, 2));
1213         IOUtils.closeQuietly(input);
1214     }
1215 
1216     @Test
1217     void testReadFully_InputStream_Offset() throws Exception {
1218         final InputStream stream = CharSequenceInputStream.builder().setCharSequence("abcd1234").setCharset(StandardCharsets.UTF_8).get();
1219         final byte[] buffer = "wx00000000".getBytes(StandardCharsets.UTF_8);
1220         IOUtils.readFully(stream, buffer, 2, 8);
1221         assertEquals("wxabcd1234", new String(buffer, 0, buffer.length, StandardCharsets.UTF_8));
1222         IOUtils.closeQuietly(stream);
1223     }
1224 
1225     @ParameterizedTest
1226     @MethodSource("invalidRead_InputStream_Offset_ArgumentsProvider")
1227     void testReadFully_InputStream_Offset_ArgumentsValidation(final InputStream input, final byte[] b, final int off, final int len,
1228             final Class<? extends Throwable> expected) {
1229         assertThrows(expected, () -> IOUtils.read(input, b, off, len));
1230     }
1231 
1232     @Test
1233     void testReadFully_ReadableByteChannel() throws Exception {
1234         final ByteBuffer buffer = ByteBuffer.allocate(FILE_SIZE);
1235         final FileInputStream fileInputStream = new FileInputStream(testFile);
1236         final FileChannel input = fileInputStream.getChannel();
1237         try {
1238             IOUtils.readFully(input, buffer);
1239             assertEquals(FILE_SIZE, buffer.position());
1240             assertEquals(0, buffer.remaining());
1241             assertEquals(0, input.read(buffer));
1242             IOUtils.readFully(input, buffer);
1243             assertEquals(FILE_SIZE, buffer.position());
1244             assertEquals(0, buffer.remaining());
1245             assertEquals(0, input.read(buffer));
1246             IOUtils.readFully(input, buffer);
1247             buffer.clear();
1248             assertThrows(EOFException.class, () -> IOUtils.readFully(input, buffer));
1249         } finally {
1250             IOUtils.closeQuietly(input, fileInputStream);
1251         }
1252     }
1253 
1254     @Test
1255     void testReadFully_Reader() throws Exception {
1256         final int size = 1027;
1257         final char[] buffer = new char[size];
1258         final Reader input = new CharArrayReader(new char[size]);
1259 
1260         IOUtils.readFully(input, buffer, 0, 0);
1261         IOUtils.readFully(input, buffer, 0, size - 3);
1262         assertThrows(IndexOutOfBoundsException.class, () -> IOUtils.readFully(input, buffer, 0, -1));
1263         assertThrows(EOFException.class, () -> IOUtils.readFully(input, buffer, 0, 5));
1264         IOUtils.closeQuietly(input);
1265     }
1266 
1267     @Test
1268     void testReadFully_Reader_Offset() throws Exception {
1269         final Reader reader = new StringReader("abcd1234");
1270         final char[] buffer = "wx00000000".toCharArray();
1271         IOUtils.readFully(reader, buffer, 2, 8);
1272         assertEquals("wxabcd1234", new String(buffer));
1273         IOUtils.closeQuietly(reader);
1274     }
1275 
1276     @Test
1277     void testReadLines_CharSequence() throws IOException {
1278         final File file = TestUtils.newFile(temporaryFolder, "lines.txt");
1279         CharSequence csq = null;
1280         try {
1281             final String[] data = {"hello", "\u1234", "", "this is", "some text"};
1282             TestUtils.createLineFileUtf8(file, data);
1283             csq = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
1284             final List<String> lines = IOUtils.readLines(csq);
1285             assertEquals(Arrays.asList(data), lines);
1286         } finally {
1287             TestUtils.deleteFile(file);
1288         }
1289     }
1290 
1291     @Test
1292     void testReadLines_CharSequenceAsStringBuilder() throws IOException {
1293         final File file = TestUtils.newFile(temporaryFolder, "lines.txt");
1294         StringBuilder csq = null;
1295         try {
1296             final String[] data = {"hello", "\u1234", "", "this is", "some text"};
1297             TestUtils.createLineFileUtf8(file, data);
1298             csq = new StringBuilder(new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8));
1299             final List<String> lines = IOUtils.readLines(csq);
1300             assertEquals(Arrays.asList(data), lines);
1301         } finally {
1302             TestUtils.deleteFile(file);
1303         }
1304     }
1305 
1306     @Test
1307     void testReadLines_InputStream() throws Exception {
1308         final File file = TestUtils.newFile(temporaryFolder, "lines.txt");
1309         InputStream in = null;
1310         try {
1311             final String[] data = {"hello", "world", "", "this is", "some text"};
1312             TestUtils.createLineFileUtf8(file, data);
1313 
1314             in = Files.newInputStream(file.toPath());
1315             final List<String> lines = IOUtils.readLines(in);
1316             assertEquals(Arrays.asList(data), lines);
1317             assertEquals(-1, in.read());
1318         } finally {
1319             IOUtils.closeQuietly(in);
1320             TestUtils.deleteFile(file);
1321         }
1322     }
1323 
1324     @Test
1325     void testReadLines_InputStream_String() throws Exception {
1326         final File file = TestUtils.newFile(temporaryFolder, "lines.txt");
1327         InputStream in = null;
1328         try {
1329             final String[] data = { "\u4f60\u597d", "hello", "\u1234", "", "this is", "some text" };
1330             TestUtils.createLineFileUtf8(file, data);
1331             in = Files.newInputStream(file.toPath());
1332             final List<String> lines = IOUtils.readLines(in, UTF_8);
1333             assertEquals(Arrays.asList(data), lines);
1334             assertEquals(-1, in.read());
1335         } finally {
1336             IOUtils.closeQuietly(in);
1337             TestUtils.deleteFile(file);
1338         }
1339     }
1340 
1341     @Test
1342     void testReadLines_Reader() throws Exception {
1343         final File file = TestUtils.newFile(temporaryFolder, "lines.txt");
1344         Reader in = null;
1345         try {
1346             // Don't use non-ASCII in this test fixture because this test uses the default platform encoding.
1347             final String[] data = {"hello", "1234", "", "this is", "some text"};
1348             TestUtils.createLineFileUtf8(file, data);
1349             in = new InputStreamReader(Files.newInputStream(file.toPath()));
1350             final List<String> lines = IOUtils.readLines(in);
1351             assertEquals(Arrays.asList(data), lines);
1352             assertEquals(-1, in.read());
1353         } finally {
1354             IOUtils.closeQuietly(in);
1355             TestUtils.deleteFile(file);
1356         }
1357     }
1358 
1359     @Test
1360     void testResourceToByteArray_ExistingResourceAtRootPackage() throws Exception {
1361         final long fileSize = TestResources.getFile("test-file-utf8.bin").length();
1362         final byte[] bytes = IOUtils.resourceToByteArray("/org/apache/commons/io/test-file-utf8.bin");
1363         assertNotNull(bytes);
1364         assertEquals(fileSize, bytes.length);
1365     }
1366 
1367     @Test
1368     void testResourceToByteArray_ExistingResourceAtRootPackage_WithClassLoader() throws Exception {
1369         final long fileSize = TestResources.getFile("test-file-utf8.bin").length();
1370         final byte[] bytes = IOUtils.resourceToByteArray("org/apache/commons/io/test-file-utf8.bin",
1371             ClassLoader.getSystemClassLoader());
1372         assertNotNull(bytes);
1373         assertEquals(fileSize, bytes.length);
1374     }
1375 
1376     @Test
1377     void testResourceToByteArray_ExistingResourceAtSubPackage() throws Exception {
1378         final long fileSize = TestResources.getFile("FileUtilsTestDataCR.bin").length();
1379         final byte[] bytes = IOUtils.resourceToByteArray("/org/apache/commons/io/FileUtilsTestDataCR.bin");
1380         assertNotNull(bytes);
1381         assertEquals(fileSize, bytes.length);
1382     }
1383 
1384     @Test
1385     void testResourceToByteArray_ExistingResourceAtSubPackage_WithClassLoader() throws Exception {
1386         final long fileSize = TestResources.getFile("FileUtilsTestDataCR.bin").length();
1387         final byte[] bytes = IOUtils.resourceToByteArray("org/apache/commons/io/FileUtilsTestDataCR.bin",
1388             ClassLoader.getSystemClassLoader());
1389         assertNotNull(bytes);
1390         assertEquals(fileSize, bytes.length);
1391     }
1392 
1393     @Test
1394     void testResourceToByteArray_NonExistingResource() {
1395         assertThrows(IOException.class, () -> IOUtils.resourceToByteArray("/non-existing-file.bin"));
1396     }
1397 
1398     @Test
1399     void testResourceToByteArray_NonExistingResource_WithClassLoader() {
1400         assertThrows(IOException.class,
1401             () -> IOUtils.resourceToByteArray("non-existing-file.bin", ClassLoader.getSystemClassLoader()));
1402     }
1403 
1404     @Test
1405     void testResourceToByteArray_Null() {
1406         assertThrows(NullPointerException.class, () -> IOUtils.resourceToByteArray(null));
1407     }
1408 
1409     @Test
1410     void testResourceToByteArray_Null_WithClassLoader() {
1411         assertThrows(NullPointerException.class,
1412             () -> IOUtils.resourceToByteArray(null, ClassLoader.getSystemClassLoader()));
1413     }
1414 
1415     @Test
1416     void testResourceToString_ExistingResourceAtRootPackage() throws Exception {
1417         final long fileSize = TestResources.getFile("test-file-simple-utf8.bin").length();
1418         final String content = IOUtils.resourceToString("/org/apache/commons/io/test-file-simple-utf8.bin",
1419             StandardCharsets.UTF_8);
1420 
1421         assertNotNull(content);
1422         assertEquals(fileSize, content.getBytes().length);
1423     }
1424 
1425     // Tests from IO-305
1426 
1427     @Test
1428     void testResourceToString_ExistingResourceAtRootPackage_WithClassLoader() throws Exception {
1429         final long fileSize = TestResources.getFile("test-file-simple-utf8.bin").length();
1430         final String content = IOUtils.resourceToString("org/apache/commons/io/test-file-simple-utf8.bin",
1431             StandardCharsets.UTF_8, ClassLoader.getSystemClassLoader());
1432 
1433         assertNotNull(content);
1434         assertEquals(fileSize, content.getBytes().length);
1435     }
1436 
1437     @Test
1438     void testResourceToString_ExistingResourceAtSubPackage() throws Exception {
1439         final long fileSize = TestResources.getFile("FileUtilsTestDataCR.bin").length();
1440         final String content = IOUtils.resourceToString("/org/apache/commons/io/FileUtilsTestDataCR.bin",
1441             StandardCharsets.UTF_8);
1442 
1443         assertNotNull(content);
1444         assertEquals(fileSize, content.getBytes().length);
1445     }
1446 
1447     @Test
1448     void testResourceToString_ExistingResourceAtSubPackage_WithClassLoader() throws Exception {
1449         final long fileSize = TestResources.getFile("FileUtilsTestDataCR.bin").length();
1450         final String content = IOUtils.resourceToString("org/apache/commons/io/FileUtilsTestDataCR.bin",
1451             StandardCharsets.UTF_8, ClassLoader.getSystemClassLoader());
1452 
1453         assertNotNull(content);
1454         assertEquals(fileSize, content.getBytes().length);
1455     }
1456 
1457     @Test
1458     void testResourceToString_NonExistingResource() {
1459         assertThrows(IOException.class,
1460             () -> IOUtils.resourceToString("/non-existing-file.bin", StandardCharsets.UTF_8));
1461     }
1462 
1463     @Test
1464     void testResourceToString_NonExistingResource_WithClassLoader() {
1465         assertThrows(IOException.class, () -> IOUtils.resourceToString("non-existing-file.bin", StandardCharsets.UTF_8,
1466             ClassLoader.getSystemClassLoader()));
1467     }
1468 
1469     @SuppressWarnings("squid:S2699") // Suppress "Add at least one assertion to this test case"
1470     @Test
1471     void testResourceToString_NullCharset() throws Exception {
1472         IOUtils.resourceToString("/org/apache/commons/io//test-file-utf8.bin", null);
1473     }
1474 
1475     @SuppressWarnings("squid:S2699") // Suppress "Add at least one assertion to this test case"
1476     @Test
1477     void testResourceToString_NullCharset_WithClassLoader() throws Exception {
1478         IOUtils.resourceToString("org/apache/commons/io/test-file-utf8.bin", null, ClassLoader.getSystemClassLoader());
1479     }
1480 
1481     @Test
1482     void testResourceToString_NullResource() {
1483         assertThrows(NullPointerException.class, () -> IOUtils.resourceToString(null, StandardCharsets.UTF_8));
1484     }
1485 
1486     @Test
1487     void testResourceToString_NullResource_WithClassLoader() {
1488         assertThrows(NullPointerException.class,
1489             () -> IOUtils.resourceToString(null, StandardCharsets.UTF_8, ClassLoader.getSystemClassLoader()));
1490     }
1491 
1492     @Test
1493     void testResourceToURL_ExistingResourceAtRootPackage() throws Exception {
1494         final URL url = IOUtils.resourceToURL("/org/apache/commons/io/test-file-utf8.bin");
1495         assertNotNull(url);
1496         assertTrue(url.getFile().endsWith("/test-file-utf8.bin"));
1497     }
1498 
1499     @Test
1500     void testResourceToURL_ExistingResourceAtRootPackage_WithClassLoader() throws Exception {
1501         final URL url = IOUtils.resourceToURL("org/apache/commons/io/test-file-utf8.bin",
1502             ClassLoader.getSystemClassLoader());
1503         assertNotNull(url);
1504         assertTrue(url.getFile().endsWith("/org/apache/commons/io/test-file-utf8.bin"));
1505     }
1506 
1507     @Test
1508     void testResourceToURL_ExistingResourceAtSubPackage() throws Exception {
1509         final URL url = IOUtils.resourceToURL("/org/apache/commons/io/FileUtilsTestDataCR.bin");
1510         assertNotNull(url);
1511         assertTrue(url.getFile().endsWith("/org/apache/commons/io/FileUtilsTestDataCR.bin"));
1512     }
1513 
1514     @Test
1515     void testResourceToURL_ExistingResourceAtSubPackage_WithClassLoader() throws Exception {
1516         final URL url = IOUtils.resourceToURL("org/apache/commons/io/FileUtilsTestDataCR.bin",
1517             ClassLoader.getSystemClassLoader());
1518 
1519         assertNotNull(url);
1520         assertTrue(url.getFile().endsWith("/org/apache/commons/io/FileUtilsTestDataCR.bin"));
1521     }
1522 
1523     @Test
1524     void testResourceToURL_NonExistingResource() {
1525         assertThrows(IOException.class, () -> IOUtils.resourceToURL("/non-existing-file.bin"));
1526     }
1527 
1528     @Test
1529     void testResourceToURL_NonExistingResource_WithClassLoader() {
1530         assertThrows(IOException.class,
1531             () -> IOUtils.resourceToURL("non-existing-file.bin", ClassLoader.getSystemClassLoader()));
1532     }
1533 
1534     @Test
1535     void testResourceToURL_Null() {
1536         assertThrows(NullPointerException.class, () -> IOUtils.resourceToURL(null));
1537     }
1538 
1539     @Test
1540     void testResourceToURL_Null_WithClassLoader() {
1541         assertThrows(NullPointerException.class, () -> IOUtils.resourceToURL(null, ClassLoader.getSystemClassLoader()));
1542     }
1543 
1544     void testSingleEOL(final String s1, final String s2, final boolean ifEquals) {
1545         assertEquals(ifEquals, IOUtils.contentEqualsIgnoreEOL(
1546                 new CharArrayReader(s1.toCharArray()),
1547                 new CharArrayReader(s2.toCharArray())
1548         ), "failed at :{" + s1 + "," + s2 + "}");
1549         assertEquals(ifEquals, IOUtils.contentEqualsIgnoreEOL(
1550                 new CharArrayReader(s2.toCharArray()),
1551                 new CharArrayReader(s1.toCharArray())
1552         ), "failed at :{" + s2 + "," + s1 + "}");
1553         assertTrue(IOUtils.contentEqualsIgnoreEOL(
1554                 new CharArrayReader(s1.toCharArray()),
1555                 new CharArrayReader(s1.toCharArray())
1556         ), "failed at :{" + s1 + "," + s1 + "}");
1557         assertTrue(IOUtils.contentEqualsIgnoreEOL(
1558                 new CharArrayReader(s2.toCharArray()),
1559                 new CharArrayReader(s2.toCharArray())
1560         ), "failed at :{" + s2 + "," + s2 + "}");
1561     }
1562 
1563     @Test
1564     void testSkip_FileReader() throws Exception {
1565         try (Reader in = Files.newBufferedReader(testFilePath)) {
1566             assertEquals(FILE_SIZE - 10, IOUtils.skip(in, FILE_SIZE - 10));
1567             assertEquals(10, IOUtils.skip(in, 20));
1568             assertEquals(0, IOUtils.skip(in, 10));
1569         }
1570     }
1571 
1572     @Test
1573     void testSkip_InputStream() throws Exception {
1574         try (InputStream in = Files.newInputStream(testFilePath)) {
1575             assertEquals(FILE_SIZE - 10, IOUtils.skip(in, FILE_SIZE - 10));
1576             assertEquals(10, IOUtils.skip(in, 20));
1577             assertEquals(0, IOUtils.skip(in, 10));
1578         }
1579     }
1580 
1581     @Test
1582     void testSkip_ReadableByteChannel() throws Exception {
1583         final FileInputStream fileInputStream = new FileInputStream(testFile);
1584         final FileChannel fileChannel = fileInputStream.getChannel();
1585         try {
1586             assertEquals(FILE_SIZE - 10, IOUtils.skip(fileChannel, FILE_SIZE - 10));
1587             assertEquals(10, IOUtils.skip(fileChannel, 20));
1588             assertEquals(0, IOUtils.skip(fileChannel, 10));
1589         } finally {
1590             IOUtils.closeQuietly(fileChannel, fileInputStream);
1591         }
1592     }
1593 
1594     @Test
1595     void testSkipFully_InputStream() throws Exception {
1596         final int size = 1027;
1597         try (InputStream input = new ByteArrayInputStream(new byte[size])) {
1598             assertThrows(IllegalArgumentException.class, () -> IOUtils.skipFully(input, -1));
1599             IOUtils.skipFully(input, 0);
1600             IOUtils.skipFully(input, size - 1);
1601             assertThrows(IOException.class, () -> IOUtils.skipFully(input, 2));
1602         }
1603     }
1604 
1605     @Test
1606     void testSkipFully_InputStream_Buffer_New_bytes() throws Exception {
1607         final int size = 1027;
1608         final Supplier<byte[]> bas = () -> new byte[size];
1609         try (InputStream input = new ByteArrayInputStream(new byte[size])) {
1610             assertThrows(IllegalArgumentException.class, () -> IOUtils.skipFully(input, -1, bas));
1611             IOUtils.skipFully(input, 0, bas);
1612             IOUtils.skipFully(input, size - 1, bas);
1613             assertThrows(IOException.class, () -> IOUtils.skipFully(input, 2, bas));
1614         }
1615     }
1616 
1617     @Test
1618     void testSkipFully_InputStream_Buffer_Reuse_bytes() throws Exception {
1619         final int size = 1027;
1620         final byte[] ba = new byte[size];
1621         final Supplier<byte[]> bas = () -> ba;
1622         try (InputStream input = new ByteArrayInputStream(new byte[size])) {
1623             assertThrows(IllegalArgumentException.class, () -> IOUtils.skipFully(input, -1, bas));
1624             IOUtils.skipFully(input, 0, bas);
1625             IOUtils.skipFully(input, size - 1, bas);
1626             assertThrows(IOException.class, () -> IOUtils.skipFully(input, 2, bas));
1627         }
1628     }
1629 
1630     @Test
1631     void testSkipFully_InputStream_Buffer_Reuse_ThreadLocal() throws Exception {
1632         final int size = 1027;
1633         final ThreadLocal<byte[]> tl = ThreadLocal.withInitial(() -> new byte[size]);
1634         try (InputStream input = new ByteArrayInputStream(new byte[size])) {
1635             assertThrows(IllegalArgumentException.class, () -> IOUtils.skipFully(input, -1, tl::get));
1636             IOUtils.skipFully(input, 0, tl::get);
1637             IOUtils.skipFully(input, size - 1, tl::get);
1638             assertThrows(IOException.class, () -> IOUtils.skipFully(input, 2, tl::get));
1639         }
1640     }
1641 
1642     @Test
1643     void testSkipFully_ReadableByteChannel() throws Exception {
1644         final FileInputStream fileInputStream = new FileInputStream(testFile);
1645         final FileChannel fileChannel = fileInputStream.getChannel();
1646         try {
1647             assertThrows(IllegalArgumentException.class, () -> IOUtils.skipFully(fileChannel, -1));
1648             IOUtils.skipFully(fileChannel, 0);
1649             IOUtils.skipFully(fileChannel, FILE_SIZE - 1);
1650             assertThrows(IOException.class, () -> IOUtils.skipFully(fileChannel, 2));
1651         } finally {
1652             IOUtils.closeQuietly(fileChannel, fileInputStream);
1653         }
1654     }
1655 
1656     @Test
1657     void testSkipFully_Reader() throws Exception {
1658         final int size = 1027;
1659         try (Reader input = new CharArrayReader(new char[size])) {
1660             IOUtils.skipFully(input, 0);
1661             IOUtils.skipFully(input, size - 3);
1662             assertThrows(IllegalArgumentException.class, () -> IOUtils.skipFully(input, -1));
1663             assertThrows(IOException.class, () -> IOUtils.skipFully(input, 5));
1664         }
1665     }
1666 
1667     @Test
1668     void testStringToOutputStream() throws Exception {
1669         final File destination = TestUtils.newFile(temporaryFolder, "copy5.txt");
1670         final String str;
1671         try (Reader fin = Files.newBufferedReader(testFilePath)) {
1672             // Create our String. Rely on testReaderToString() to make sure this is valid.
1673             str = IOUtils.toString(fin);
1674         }
1675         try (OutputStream fout = Files.newOutputStream(destination.toPath())) {
1676             CopyUtils.copy(str, fout);
1677             // Note: this method *does* flush. It is equivalent to:
1678             // OutputStreamWriter _out = new OutputStreamWriter(fout);
1679             // CopyUtils.copy( str, _out, 4096 ); // copy( Reader, Writer, int );
1680             // _out.flush();
1681             // out = fout;
1682             // note: we don't flush here; this IOUtils method does it for us
1683             TestUtils.checkFile(destination, testFile);
1684             TestUtils.checkWrite(fout);
1685         }
1686         TestUtils.deleteFile(destination);
1687     }
1688 
1689     @Test
1690     void testToBufferedInputStream_InputStream() throws Exception {
1691         try (InputStream fin = Files.newInputStream(testFilePath)) {
1692             final InputStream in = IOUtils.toBufferedInputStream(fin);
1693             final byte[] out = IOUtils.toByteArray(in);
1694             assertNotNull(out);
1695             assertEquals(0, fin.available(), "Not all bytes were read");
1696             assertEquals(FILE_SIZE, out.length, "Wrong output size");
1697             TestUtils.assertEqualContent(out, testFile);
1698         }
1699     }
1700 
1701     @Test
1702     void testToBufferedInputStreamWithBufferSize_InputStream() throws Exception {
1703         try (InputStream fin = Files.newInputStream(testFilePath)) {
1704             final InputStream in = IOUtils.toBufferedInputStream(fin, 2048);
1705             final byte[] out = IOUtils.toByteArray(in);
1706             assertNotNull(out);
1707             assertEquals(0, fin.available(), "Not all bytes were read");
1708             assertEquals(FILE_SIZE, out.length, "Wrong output size");
1709             TestUtils.assertEqualContent(out, testFile);
1710         }
1711     }
1712 
1713     @Test
1714     void testToByteArray_InputStream() throws Exception {
1715         try (InputStream fin = Files.newInputStream(testFilePath)) {
1716             final byte[] out = IOUtils.toByteArray(fin);
1717             assertNotNull(out);
1718             assertEquals(0, fin.available(), "Not all bytes were read");
1719             assertEquals(FILE_SIZE, out.length, "Wrong output size");
1720             TestUtils.assertEqualContent(out, testFile);
1721         }
1722     }
1723 
1724     @Test
1725     @Disabled("Disable by default as it uses too much memory and can cause builds to fail.")
1726     void testToByteArray_InputStream_LongerThanIntegerMaxValue() throws Exception {
1727         final CircularInputStream cin = new CircularInputStream(IOUtils.byteArray(), Integer.MAX_VALUE + 1L);
1728         assertThrows(IllegalArgumentException.class, () -> IOUtils.toByteArray(cin));
1729     }
1730 
1731     @Test
1732     void testToByteArray_InputStream_NegativeSize() throws Exception {
1733         try (InputStream fin = Files.newInputStream(testFilePath)) {
1734             final IllegalArgumentException exc = assertThrows(IllegalArgumentException.class, () -> IOUtils.toByteArray(fin, -1));
1735             assertTrue(exc.getMessage().startsWith("size < 0"), exc.getMessage());
1736         }
1737     }
1738 
1739     @Test
1740     void testToByteArray_InputStream_Size() throws Exception {
1741         try (InputStream fin = Files.newInputStream(testFilePath)) {
1742             final byte[] out = IOUtils.toByteArray(fin, testFile.length());
1743             assertNotNull(out);
1744             assertEquals(0, fin.available(), "Not all bytes were read");
1745             assertEquals(FILE_SIZE, out.length, "Wrong output size: out.length=" + out.length + "!=" + FILE_SIZE);
1746             TestUtils.assertEqualContent(out, testFile);
1747         }
1748     }
1749 
1750     @ParameterizedTest
1751     @MethodSource
1752     void testToByteArray_InputStream_Size_BufferSize_Succeeds(final byte[] data, final int size, final int bufferSize) throws IOException {
1753         final ByteArrayInputStream input = new ByteArrayInputStream(data);
1754         final byte[] expected = Arrays.copyOf(data, size);
1755         final byte[] actual = IOUtils.toByteArray(input, size, bufferSize);
1756         assertArrayEquals(expected, actual);
1757     }
1758 
1759     @ParameterizedTest
1760     @MethodSource
1761     void testToByteArray_InputStream_Size_BufferSize_Throws(
1762             final int size, final int bufferSize, final Class<? extends Exception> exceptionClass) throws IOException {
1763         try (InputStream input = new NullInputStream(0)) {
1764             assertThrows(exceptionClass, () -> IOUtils.toByteArray(input, size, bufferSize));
1765         }
1766     }
1767 
1768     @Test
1769     void testToByteArray_InputStream_Size_Truncated() throws Exception {
1770         try (InputStream in = new NullInputStream(0)) {
1771             assertThrows(EOFException.class, () -> IOUtils.toByteArray(in, 1));
1772         }
1773     }
1774 
1775     @Test
1776     void testToByteArray_InputStream_SizeIllegal() throws Exception {
1777         try (InputStream fin = Files.newInputStream(testFilePath)) {
1778             final IOException exc = assertThrows(IOException.class, () -> IOUtils.toByteArray(fin, testFile.length() + 1));
1779             assertTrue(exc.getMessage().startsWith("Expected read size"), exc.getMessage());
1780         }
1781     }
1782 
1783     @Test
1784     void testToByteArray_InputStream_SizeLong() throws Exception {
1785         try (InputStream fin = Files.newInputStream(testFilePath)) {
1786             final IllegalArgumentException exc = assertThrows(IllegalArgumentException.class, () -> IOUtils.toByteArray(fin, (long) Integer.MAX_VALUE + 1));
1787             assertTrue(exc.getMessage().startsWith("size > Integer.MAX_VALUE"), exc.getMessage());
1788         }
1789     }
1790 
1791     @Test
1792     void testToByteArray_InputStream_SizeOne() throws Exception {
1793         try (InputStream fin = Files.newInputStream(testFilePath)) {
1794             final byte[] out = IOUtils.toByteArray(fin, 1);
1795             assertNotNull(out, "Out cannot be null");
1796             assertEquals(1, out.length, "Out length must be 1");
1797         }
1798     }
1799 
1800     @Test
1801     void testToByteArray_InputStream_SizeZero() throws Exception {
1802         try (InputStream fin = Files.newInputStream(testFilePath)) {
1803             final byte[] out = IOUtils.toByteArray(fin, 0);
1804             assertNotNull(out, "Out cannot be null");
1805             assertEquals(0, out.length, "Out length must be 0");
1806         }
1807     }
1808 
1809     @Test
1810     void testToByteArray_Reader() throws IOException {
1811         final String charsetName = UTF_8;
1812         final byte[] expected = charsetName.getBytes(charsetName);
1813         byte[] actual = IOUtils.toByteArray(new InputStreamReader(new ByteArrayInputStream(expected)));
1814         assertArrayEquals(expected, actual);
1815         actual = IOUtils.toByteArray(new InputStreamReader(new ByteArrayInputStream(expected)), charsetName);
1816         assertArrayEquals(expected, actual);
1817     }
1818 
1819     @Test
1820     void testToByteArray_String() throws Exception {
1821         try (Reader fin = Files.newBufferedReader(testFilePath)) {
1822             // Create our String. Rely on testReaderToString() to make sure this is valid.
1823             final String str = IOUtils.toString(fin);
1824             final byte[] out = IOUtils.toByteArray(str);
1825             assertEqualContent(str.getBytes(), out);
1826         }
1827     }
1828 
1829     @Test
1830     void testToByteArray_ThrowsIOExceptionOnHugeStream() throws IOException {
1831         try (MockedStatic<IOUtils> utils = Mockito.mockStatic(IOUtils.class, Mockito.CALLS_REAL_METHODS);
1832                 UnsynchronizedByteArrayOutputStream mockOutputStream = mock(UnsynchronizedByteArrayOutputStream.class)) {
1833             // Prepare the mocks
1834             utils.when(() -> IOUtils.copyToOutputStream(ArgumentMatchers.any(InputStream.class), ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
1835                     .thenReturn(mockOutputStream);
1836             when(mockOutputStream.size()).thenReturn(IOUtils.SOFT_MAX_ARRAY_LENGTH + 1);
1837             // Test and check
1838             try (InputStream mockInputStream = mock(InputStream.class)) {
1839                 final IOException exception = assertThrows(IOException.class, () -> IOUtils.toByteArray(mockInputStream));
1840                 assertTrue(exception.getMessage().contains(String.format("%,d", IOUtils.SOFT_MAX_ARRAY_LENGTH)),
1841                         "Exception message does not contain the maximum length");
1842             }
1843         }
1844     }
1845 
1846     @Test
1847     void testToByteArray_URI() throws Exception {
1848         final URI url = testFile.toURI();
1849         final byte[] actual = IOUtils.toByteArray(url);
1850         assertEquals(FILE_SIZE, actual.length);
1851     }
1852 
1853     @Test
1854     void testToByteArray_URL() throws Exception {
1855         final URL url = testFile.toURI().toURL();
1856         final byte[] actual = IOUtils.toByteArray(url);
1857         assertEquals(FILE_SIZE, actual.length);
1858     }
1859 
1860     @Test
1861     void testToByteArray_URLConnection() throws Exception {
1862         final byte[] actual;
1863         try (CloseableURLConnection urlConnection = CloseableURLConnection.open(testFile.toURI())) {
1864             actual = IOUtils.toByteArray(urlConnection);
1865         }
1866         assertEquals(FILE_SIZE, actual.length);
1867     }
1868 
1869     @Test
1870     void testToCharArray_InputStream() throws Exception {
1871         try (InputStream fin = Files.newInputStream(testFilePath)) {
1872             final char[] out = IOUtils.toCharArray(fin);
1873             assertNotNull(out);
1874             assertEquals(0, fin.available(), "Not all chars were read");
1875             assertEquals(FILE_SIZE, out.length, "Wrong output size");
1876             TestUtils.assertEqualContent(out, testFile);
1877         }
1878     }
1879 
1880     @Test
1881     void testToCharArray_InputStream_CharsetName() throws Exception {
1882         try (InputStream fin = Files.newInputStream(testFilePath)) {
1883             final char[] out = IOUtils.toCharArray(fin, UTF_8);
1884             assertNotNull(out);
1885             assertEquals(0, fin.available(), "Not all chars were read");
1886             assertEquals(FILE_SIZE, out.length, "Wrong output size");
1887             TestUtils.assertEqualContent(out, testFile);
1888         }
1889     }
1890 
1891     @Test
1892     void testToCharArray_Reader() throws Exception {
1893         try (Reader fr = Files.newBufferedReader(testFilePath)) {
1894             final char[] out = IOUtils.toCharArray(fr);
1895             assertNotNull(out);
1896             assertEquals(FILE_SIZE, out.length, "Wrong output size");
1897             TestUtils.assertEqualContent(out, testFile);
1898         }
1899     }
1900 
1901     /**
1902      * Test for {@link IOUtils#toInputStream(CharSequence)} and {@link IOUtils#toInputStream(CharSequence, String)}.
1903      * Note, this test utilizes on {@link IOUtils#toByteArray(InputStream)} and so relies on
1904      * {@link #testToByteArray_InputStream()} to ensure this method functions correctly.
1905      *
1906      * @throws Exception on error
1907      */
1908     @Test
1909     void testToInputStream_CharSequence() throws Exception {
1910         final CharSequence csq = new StringBuilder("Abc123Xyz!");
1911         InputStream inStream = IOUtils.toInputStream(csq); // deliberately testing deprecated method
1912         byte[] bytes = IOUtils.toByteArray(inStream);
1913         assertEqualContent(csq.toString().getBytes(), bytes);
1914         inStream = IOUtils.toInputStream(csq, (String) null);
1915         bytes = IOUtils.toByteArray(inStream);
1916         assertEqualContent(csq.toString().getBytes(), bytes);
1917         inStream = IOUtils.toInputStream(csq, UTF_8);
1918         bytes = IOUtils.toByteArray(inStream);
1919         assertEqualContent(csq.toString().getBytes(StandardCharsets.UTF_8), bytes);
1920     }
1921 
1922     /**
1923      * Test for {@link IOUtils#toInputStream(String)} and {@link IOUtils#toInputStream(String, String)}. Note, this test
1924      * utilizes on {@link IOUtils#toByteArray(InputStream)} and so relies on
1925      * {@link #testToByteArray_InputStream()} to ensure this method functions correctly.
1926      *
1927      * @throws Exception on error
1928      */
1929     @Test
1930     void testToInputStream_String() throws Exception {
1931         final String str = "Abc123Xyz!";
1932         InputStream inStream = IOUtils.toInputStream(str);
1933         byte[] bytes = IOUtils.toByteArray(inStream);
1934         assertEqualContent(str.getBytes(), bytes);
1935         inStream = IOUtils.toInputStream(str, (String) null);
1936         bytes = IOUtils.toByteArray(inStream);
1937         assertEqualContent(str.getBytes(), bytes);
1938         inStream = IOUtils.toInputStream(str, UTF_8);
1939         bytes = IOUtils.toByteArray(inStream);
1940         assertEqualContent(str.getBytes(StandardCharsets.UTF_8), bytes);
1941     }
1942 
1943     @Test
1944     void testToString_ByteArray() throws Exception {
1945         try (InputStream fin = Files.newInputStream(testFilePath)) {
1946             final byte[] in = IOUtils.toByteArray(fin);
1947             // Create our byte[]. Rely on testInputStreamToByteArray() to make sure this is valid.
1948             final String str = IOUtils.toString(in);
1949             assertEqualContent(in, str.getBytes());
1950         }
1951     }
1952 
1953     @Test
1954     void testToString_InputStream() throws Exception {
1955         try (InputStream fin = Files.newInputStream(testFilePath)) {
1956             final String out = IOUtils.toString(fin);
1957             assertNotNull(out);
1958             assertEquals(0, fin.available(), "Not all bytes were read");
1959             assertEquals(FILE_SIZE, out.length(), "Wrong output size");
1960         }
1961     }
1962 
1963     @Test
1964     void testToString_InputStreamSupplier() throws Exception {
1965         final String out = IOUtils.toString(() -> Files.newInputStream(testFilePath), Charset.defaultCharset());
1966         assertNotNull(out);
1967         assertEquals(FILE_SIZE, out.length(), "Wrong output size");
1968         assertNull(IOUtils.toString(null, Charset.defaultCharset(), () -> null));
1969         assertNull(IOUtils.toString(() -> null, Charset.defaultCharset(), () -> null));
1970         assertEquals("A", IOUtils.toString(null, Charset.defaultCharset(), () -> "A"));
1971     }
1972 
1973     @Test
1974     void testToString_Reader() throws Exception {
1975         try (Reader fin = Files.newBufferedReader(testFilePath)) {
1976             final String out = IOUtils.toString(fin);
1977             assertNotNull(out);
1978             assertEquals(FILE_SIZE, out.length(), "Wrong output size");
1979         }
1980     }
1981 
1982     @Test
1983     void testToString_URI() throws Exception {
1984         final URI url = testFile.toURI();
1985         final String out = IOUtils.toString(url);
1986         assertNotNull(out);
1987         assertEquals(FILE_SIZE, out.length(), "Wrong output size");
1988     }
1989 
1990     private void testToString_URI(final String encoding) throws Exception {
1991         final URI uri = testFile.toURI();
1992         final String out = IOUtils.toString(uri, encoding);
1993         assertNotNull(out);
1994         assertEquals(FILE_SIZE, out.length(), "Wrong output size");
1995     }
1996 
1997     @Test
1998     void testToString_URI_CharsetName() throws Exception {
1999         testToString_URI(StandardCharsets.US_ASCII.name());
2000     }
2001 
2002     @Test
2003     void testToString_URI_CharsetNameNull() throws Exception {
2004         testToString_URI(null);
2005     }
2006 
2007     @Test
2008     void testToString_URL() throws Exception {
2009         final URL url = testFile.toURI().toURL();
2010         final String out = IOUtils.toString(url);
2011         assertNotNull(out);
2012         assertEquals(FILE_SIZE, out.length(), "Wrong output size");
2013     }
2014 
2015     private void testToString_URL(final String encoding) throws Exception {
2016         final URL url = testFile.toURI().toURL();
2017         final String out = IOUtils.toString(url, encoding);
2018         assertNotNull(out);
2019         assertEquals(FILE_SIZE, out.length(), "Wrong output size");
2020     }
2021 
2022     @Test
2023     void testToString_URL_CharsetName() throws Exception {
2024         testToString_URL(StandardCharsets.US_ASCII.name());
2025     }
2026 
2027     @Test
2028     void testToString_URL_CharsetNameNull() throws Exception {
2029         testToString_URL(null);
2030     }
2031 
2032     /**
2033      * IO-764 IOUtils.write() throws NegativeArraySizeException while writing big strings.
2034      * <pre>
2035      * java.lang.OutOfMemoryError: Java heap space
2036      *     at java.lang.StringCoding.encode(StringCoding.java:350)
2037      *     at java.lang.String.getBytes(String.java:941)
2038      *     at org.apache.commons.io.IOUtils.write(IOUtils.java:3367)
2039      *     at org.apache.commons.io.IOUtilsTest.testBigString(IOUtilsTest.java:1659)
2040      * </pre>
2041      */
2042     @Test
2043     void testWriteBigString() throws IOException {
2044         // 3_000_000 is a size that we can allocate for the test string with Java 8 on the command line as:
2045         // mvn clean test -Dtest=IOUtilsTest -DtestBigString=3000000
2046         // 6_000_000 failed with the above
2047         //
2048         // TODO Can we mock the test string for this test to pretend to be larger?
2049         // Mocking the length seems simple but how about the data?
2050         final int repeat = Integer.getInteger("testBigString", 3_000_000);
2051         final String data;
2052         try {
2053             data = StringUtils.repeat("\uD83D", repeat);
2054         } catch (final OutOfMemoryError e) {
2055             System.err.printf("Don't fail the test if we cannot build the fixture, just log, fixture size = %,d%n.", repeat);
2056             e.printStackTrace();
2057             return;
2058         }
2059         try (CountingOutputStream os = new CountingOutputStream(NullOutputStream.INSTANCE)) {
2060             IOUtils.write(data, os, StandardCharsets.UTF_8);
2061             assertEquals(repeat, os.getByteCount());
2062         }
2063     }
2064 
2065     @Test
2066     void testWriteLines() throws IOException {
2067         final String[] data = {"The", "quick"};
2068         final ByteArrayOutputStream out = new ByteArrayOutputStream();
2069         IOUtils.writeLines(Arrays.asList(data), "\n", out, StandardCharsets.UTF_16.name());
2070         final String result = new String(out.toByteArray(), StandardCharsets.UTF_16);
2071         assertEquals("The\nquick\n", result);
2072     }
2073 
2074     @Test
2075     void testWriteLittleString() throws IOException {
2076         final String data = "\uD83D";
2077         // White-box test to check that not closing the internal channel is not a problem.
2078         for (int i = 0; i < 1_000_000; i++) {
2079             try (CountingOutputStream os = new CountingOutputStream(NullOutputStream.INSTANCE)) {
2080                 IOUtils.write(data, os, StandardCharsets.UTF_8);
2081                 assertEquals(data.length(), os.getByteCount());
2082             }
2083         }
2084     }
2085 }