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