View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.commons.compress.utils;
21  
22  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23  import static org.junit.jupiter.api.Assertions.assertEquals;
24  import static org.junit.jupiter.api.Assertions.assertNotNull;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  
27  import java.io.ByteArrayInputStream;
28  import java.io.ByteArrayOutputStream;
29  import java.io.EOFException;
30  import java.io.FilterInputStream;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.io.OutputStream;
34  import java.nio.ByteBuffer;
35  import java.nio.channels.ReadableByteChannel;
36  import java.nio.charset.StandardCharsets;
37  
38  import org.apache.commons.io.input.NullInputStream;
39  import org.apache.commons.io.output.NullOutputStream;
40  import org.junit.jupiter.api.Test;
41  
42  class IOUtilsTest {
43  
44      private interface StreamWrapper {
45          InputStream wrap(InputStream toWrap);
46      }
47  
48      private static void readFully(final byte[] source, final ByteBuffer b) throws IOException {
49          try (SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel(source)) {
50              IOUtils.readFully(channel, b);
51          }
52      }
53  
54      private void skip(final StreamWrapper wrapper) throws Exception {
55          final ByteArrayInputStream in = new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 });
56          try (InputStream sut = wrapper.wrap(in)) {
57              assertEquals(10, IOUtils.skip(sut, 10));
58              assertEquals(11, sut.read());
59          }
60      }
61  
62      @Test
63      void testCopy_inputStreamToOutputStream_IO84() throws Exception {
64          final long size = (long) Integer.MAX_VALUE + (long) 1;
65          final InputStream in = new NullInputStream(size);
66          final OutputStream out = NullOutputStream.INSTANCE;
67          // Test copy() method
68          assertEquals(-1, IOUtils.copy(in, out));
69          // reset the input
70          in.close();
71      }
72  
73      @Test
74      void testCopy_inputStreamToOutputStream_nullIn() {
75          final OutputStream out = new ByteArrayOutputStream();
76          assertThrows(NullPointerException.class, () -> IOUtils.copy((InputStream) null, out));
77      }
78  
79      @Test
80      void testCopy_inputStreamToOutputStream_nullOut() {
81          final InputStream in = new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 });
82          assertThrows(NullPointerException.class, () -> IOUtils.copy(in, (OutputStream) null));
83      }
84  
85      @Test
86      void testCopyOnZeroBufferSize() throws IOException {
87          assertEquals(0, IOUtils.copy(new ByteArrayInputStream(ByteUtils.EMPTY_BYTE_ARRAY), new ByteArrayOutputStream(), 0));
88      }
89  
90      @Test
91      void testCopyRangeDoesntCopyMoreThanAskedFor() throws IOException {
92          try (ByteArrayInputStream in = new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, 5 });
93                  ByteArrayOutputStream out = new ByteArrayOutputStream()) {
94              assertEquals(3, IOUtils.copyRange(in, 3, out));
95              out.close();
96              assertArrayEquals(new byte[] { 1, 2, 3 }, out.toByteArray());
97          }
98      }
99  
100     @Test
101     void testCopyRangeStopsIfThereIsNothingToCopyAnymore() throws IOException {
102         try (ByteArrayInputStream in = new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, 5 });
103                 ByteArrayOutputStream out = new ByteArrayOutputStream()) {
104             assertEquals(5, IOUtils.copyRange(in, 10, out));
105             out.close();
106             assertArrayEquals(new byte[] { 1, 2, 3, 4, 5 }, out.toByteArray());
107         }
108     }
109 
110     @Test
111     void testCopyRangeThrowsOnZeroBufferSize() throws IOException {
112         assertThrows(IllegalArgumentException.class,
113                 () -> IOUtils.copyRange(new ByteArrayInputStream(ByteUtils.EMPTY_BYTE_ARRAY), 5, new ByteArrayOutputStream(), 0));
114         assertEquals(0, IOUtils.copyRange(new ByteArrayInputStream(ByteUtils.EMPTY_BYTE_ARRAY), 5, new ByteArrayOutputStream(), 1));
115         assertEquals(0, IOUtils.copyRange(new ByteArrayInputStream(ByteUtils.EMPTY_BYTE_ARRAY), 5, null, 1));
116         assertEquals(1, IOUtils.copyRange(new ByteArrayInputStream(new byte[1]), 5, null, 1));
117     }
118 
119     @Test
120     void testReadFullyOnChannelReadsFully() throws IOException {
121         final ByteBuffer b = ByteBuffer.allocate(20);
122         final byte[] source = new byte[20];
123         for (byte i = 0; i < 20; i++) {
124             source[i] = i;
125         }
126         readFully(source, b);
127         assertArrayEquals(source, b.array());
128     }
129 
130     @Test
131     void testReadFullyOnChannelThrowsEof() {
132         final ByteBuffer b = ByteBuffer.allocate(21);
133         final byte[] source = new byte[20];
134         for (byte i = 0; i < 20; i++) {
135             source[i] = i;
136         }
137         assertThrows(EOFException.class, () -> readFully(source, b));
138     }
139 
140     @Test
141     void testReadRangeFromChannelDoesntReadMoreThanAskedFor() throws IOException {
142         try (ReadableByteChannel in = new SeekableInMemoryByteChannel(new byte[] { 1, 2, 3, 4, 5 })) {
143             final byte[] read = IOUtils.readRange(in, 3);
144             assertArrayEquals(new byte[] { 1, 2, 3 }, read);
145             final ByteBuffer b = ByteBuffer.allocate(1);
146             assertEquals(1, in.read(b));
147             assertArrayEquals(new byte[] { 4 }, b.array());
148         }
149     }
150 
151     @Test
152     void testReadRangeFromChannelDoesntReadMoreThanAskedForWhenItGotLessInFirstReadCall() throws IOException {
153         try (ReadableByteChannel in = new SeekableInMemoryByteChannel(new byte[] { 1, 2, 3, 4, 5, 6, 7 }) {
154             @Override
155             public int read(ByteBuffer buf) throws IOException {
156                 // Trickle max 2 bytes at a time to trigger COMPRESS-584
157                 final ByteBuffer temp = ByteBuffer.allocate(Math.min(2, buf.remaining()));
158                 final int read = super.read(temp);
159                 if (read > 0) {
160                     buf.put(temp.array(), 0, read);
161                 }
162                 return read;
163             }
164         }) {
165             final byte[] read = IOUtils.readRange(in, 5);
166             assertArrayEquals(new byte[] { 1, 2, 3, 4, 5 }, read);
167         }
168     }
169 
170     @Test
171     void testReadRangeFromChannelStopsIfThereIsNothingToReadAnymore() throws IOException {
172         try (ReadableByteChannel in = new SeekableInMemoryByteChannel(new byte[] { 1, 2, 3, 4, 5 })) {
173             final byte[] read = IOUtils.readRange(in, 10);
174             assertArrayEquals(new byte[] { 1, 2, 3, 4, 5 }, read);
175             final ByteBuffer b = ByteBuffer.allocate(1);
176             assertEquals(-1, in.read(b));
177         }
178     }
179 
180     @Test
181     void testReadRangeFromStreamDoesntReadMoreThanAskedFor() throws IOException {
182         try (ByteArrayInputStream in = new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, 5 })) {
183             final byte[] read = IOUtils.readRange(in, 3);
184             assertArrayEquals(new byte[] { 1, 2, 3 }, read);
185             assertEquals(4, in.read());
186         }
187     }
188 
189     @Test
190     void testReadRangeFromStreamStopsIfThereIsNothingToReadAnymore() throws IOException {
191         try (ByteArrayInputStream in = new ByteArrayInputStream(new byte[] { 1, 2, 3, 4, 5 })) {
192             final byte[] read = IOUtils.readRange(in, 10);
193             assertArrayEquals(new byte[] { 1, 2, 3, 4, 5 }, read);
194             assertEquals(-1, in.read());
195         }
196     }
197 
198     @Test
199     void testReadRangeMoreThanCopyBufferSize() throws Exception {
200         final int copyBufSize = org.apache.commons.io.IOUtils.DEFAULT_BUFFER_SIZE;
201 
202         // Make an input that requires two read loops to trigger COMPRESS-585
203         final byte[] input = new byte[copyBufSize + 10];
204 
205         try (SeekableInMemoryByteChannel in = new SeekableInMemoryByteChannel(input)) {
206             // Ask for less than the input length, but more than the buffer size
207             final int toRead = copyBufSize + 1;
208             final byte[] read = IOUtils.readRange(in, toRead);
209             assertEquals(toRead, read.length);
210             assertEquals(toRead, in.position());
211         }
212     }
213 
214     @Test
215     void testSkipUsingRead() throws Exception {
216         skip(toWrap -> new FilterInputStream(toWrap) {
217             @Override
218             public long skip(final long s) {
219                 return 0;
220             }
221         });
222     }
223 
224     @Test
225     void testSkipUsingSkip() throws Exception {
226         skip(toWrap -> toWrap);
227     }
228 
229     @Test
230     void testSkipUsingSkipAndRead() throws Exception {
231         skip(toWrap -> new FilterInputStream(toWrap) {
232             boolean skipped;
233 
234             @Override
235             public long skip(final long s) throws IOException {
236                 if (!skipped) {
237                     toWrap.skip(5);
238                     skipped = true;
239                     return 5;
240                 }
241                 return 0;
242             }
243         });
244     }
245 
246     @Test
247     void testToByteArray_InputStream() throws Exception {
248         final byte[] bytes = "ABCB".getBytes(StandardCharsets.UTF_8);
249         try (InputStream fin = new ByteArrayInputStream(bytes)) {
250             @SuppressWarnings("deprecation")
251             final byte[] out = IOUtils.toByteArray(fin);
252             assertNotNull(out);
253             assertEquals(0, fin.available());
254             assertEquals(4, out.length);
255             assertArrayEquals(bytes, out);
256         }
257     }
258 
259 }