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