View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.io.input;
18  
19  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertNotEquals;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  
26  import java.io.ByteArrayInputStream;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.nio.file.Files;
30  import java.nio.file.Paths;
31  import java.security.MessageDigest;
32  import java.util.concurrent.atomic.AtomicBoolean;
33  
34  import org.apache.commons.codec.digest.DigestUtils;
35  import org.apache.commons.codec.digest.MessageDigestAlgorithms;
36  import org.apache.commons.io.IOExceptionList;
37  import org.apache.commons.io.IOUtils;
38  import org.apache.commons.io.input.MessageDigestCalculatingInputStream.Builder;
39  import org.apache.commons.io.test.CustomIOException;
40  import org.junit.jupiter.api.Test;
41  
42  /**
43   * Tests {@link MessageDigestCalculatingInputStream}.
44   */
45  @SuppressWarnings("deprecation")
46  class MessageDigestCalculatingInputStreamTest {
47  
48      private InputStream createInputStream() throws IOException {
49          final ByteArrayInputStream origin = new ByteArrayInputStream(MessageDigestInputStreamTest.generateRandomByteStream(256));
50          return createInputStream(origin);
51      }
52  
53      private MessageDigestCalculatingInputStream createInputStream(final InputStream origin) throws IOException {
54          return MessageDigestCalculatingInputStream.builder().setInputStream(origin).get();
55      }
56  
57      @Test
58      void testAfterReadConsumer() throws Exception {
59          final AtomicBoolean boolRef = new AtomicBoolean();
60          // @formatter:off
61          try (InputStream bounded = MessageDigestCalculatingInputStream.builder()
62                  .setCharSequence("Hi")
63                  .setAfterRead(i -> boolRef.set(true))
64                  .get()) {
65              IOUtils.consume(bounded);
66          }
67          // @formatter:on
68          assertTrue(boolRef.get());
69          // Throwing
70          final String message = "test exception message";
71          // @formatter:off
72          try (InputStream bounded = MessageDigestCalculatingInputStream.builder()
73                  .setCharSequence("Hi")
74                  .setAfterRead(i -> {
75                      throw new CustomIOException(message);
76                  })
77                  .get()) {
78              assertTrue(assertThrowsExactly(IOExceptionList.class, () -> IOUtils.consume(bounded)).getMessage().contains(message));
79          }
80          // @formatter:on
81      }
82  
83      @SuppressWarnings("resource")
84      @Test
85      void testAvailableAfterClose() throws Exception {
86          final InputStream shadow;
87          try (InputStream in = createInputStream()) {
88              assertTrue(in.available() > 0);
89              shadow = in;
90          }
91          assertEquals(0, shadow.available());
92      }
93  
94      @Test
95      void testAvailableAfterOpen() throws Exception {
96          try (InputStream in = createInputStream()) {
97              assertTrue(in.available() > 0);
98              assertNotEquals(IOUtils.EOF, in.read());
99              assertTrue(in.available() > 0);
100         }
101     }
102 
103     @Test
104     void testCloseHandleIOException() throws IOException {
105         ProxyInputStreamTest.testCloseHandleIOException(MessageDigestCalculatingInputStream.builder());
106     }
107 
108     @Test
109     void testNormalUse() throws Exception {
110         for (int i = 256; i < 8192; i *= 2) {
111             final byte[] buffer = MessageDigestInputStreamTest.generateRandomByteStream(i);
112             final MessageDigest defaultMessageDigest = MessageDigestCalculatingInputStream.getDefaultMessageDigest();
113             final byte[] defaultExpect = defaultMessageDigest.digest(buffer);
114             // Defaults
115             try (MessageDigestCalculatingInputStream messageDigestInputStream = new MessageDigestCalculatingInputStream(new ByteArrayInputStream(buffer))) {
116                 messageDigestInputStream.consume();
117                 assertArrayEquals(defaultExpect, messageDigestInputStream.getMessageDigest().digest());
118             }
119             try (MessageDigestCalculatingInputStream messageDigestInputStream = MessageDigestCalculatingInputStream.builder()
120                     .setInputStream(new ByteArrayInputStream(buffer)).get()) {
121                 messageDigestInputStream.consume();
122                 assertArrayEquals(defaultExpect, messageDigestInputStream.getMessageDigest().digest());
123             }
124             try (MessageDigestCalculatingInputStream messageDigestInputStream = MessageDigestCalculatingInputStream.builder().setByteArray(buffer).get()) {
125                 messageDigestInputStream.consume();
126                 assertArrayEquals(defaultExpect, messageDigestInputStream.getMessageDigest().digest());
127             }
128             // SHA-512
129             final byte[] sha512Expect = DigestUtils.sha512(buffer);
130             {
131                 final Builder builder = MessageDigestCalculatingInputStream.builder();
132                 builder.setMessageDigest(MessageDigestAlgorithms.SHA_512);
133                 builder.setInputStream(new ByteArrayInputStream(buffer));
134                 try (MessageDigestCalculatingInputStream messageDigestInputStream = builder.get()) {
135                     messageDigestInputStream.consume();
136                     assertArrayEquals(sha512Expect, messageDigestInputStream.getMessageDigest().digest());
137                 }
138             }
139             {
140                 final Builder builder = MessageDigestCalculatingInputStream.builder();
141                 builder.setMessageDigest(MessageDigestAlgorithms.SHA_512);
142                 builder.setInputStream(new ByteArrayInputStream(buffer));
143                 try (MessageDigestCalculatingInputStream messageDigestInputStream = builder.get()) {
144                     messageDigestInputStream.consume();
145                     assertArrayEquals(sha512Expect, messageDigestInputStream.getMessageDigest().digest());
146                 }
147             }
148         }
149     }
150 
151     @Test
152     void testReadAfterClose_ByteArrayInputStream() throws Exception {
153         try (InputStream in = createInputStream()) {
154             in.close();
155             // ByteArrayInputStream does not throw on a closed stream.
156             assertNotEquals(IOUtils.EOF, in.read());
157         }
158     }
159 
160     @SuppressWarnings("resource")
161     @Test
162     void testReadAfterClose_ChannelInputStream() throws Exception {
163         try (InputStream in = createInputStream(Files.newInputStream(Paths.get("src/test/resources/org/apache/commons/io/abitmorethan16k.txt")))) {
164             in.close();
165             // ChannelInputStream throws when closed
166             assertThrows(IOException.class, in::read);
167         }
168     }
169 
170 }