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.codec.digest;
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.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  import static org.junit.jupiter.api.Assertions.fail;
24  import static org.junit.jupiter.api.Assumptions.assumeTrue;
25  
26  import java.io.ByteArrayInputStream;
27  import java.io.File;
28  import java.io.IOException;
29  import java.io.RandomAccessFile;
30  import java.lang.reflect.Field;
31  import java.lang.reflect.Modifier;
32  import java.nio.ByteBuffer;
33  import java.nio.file.OpenOption;
34  import java.nio.file.Path;
35  import java.nio.file.StandardOpenOption;
36  import java.security.MessageDigest;
37  import java.security.NoSuchAlgorithmException;
38  
39  import org.junit.jupiter.api.AfterEach;
40  import org.junit.jupiter.api.BeforeAll;
41  import org.junit.jupiter.api.BeforeEach;
42  import org.junit.jupiter.params.ParameterizedTest;
43  import org.junit.jupiter.params.provider.MethodSource;
44  
45  /**
46   * Tests {@link MessageDigestAlgorithms}.
47   */
48  class MessageDigestAlgorithmsTest {
49  
50      @BeforeAll
51      public static void checkValues() throws Exception {
52          final Field[] fields = MessageDigestAlgorithms.class.getDeclaredFields();
53          boolean ok = true;
54          int psf = 0;
55          for (final Field field : fields) {
56              // Ignore Cobertura instrumentation fields
57              final String name = field.getName();
58              if (name.contains("cobertura")) {
59                  continue;
60              }
61              // Only interested in public fields
62              final int modifiers = field.getModifiers();
63              if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
64                  psf++;
65                  // SHAKE128_256 and SHAKE128_512 are only in Java 25 and up.
66                  if (!contains((String) field.get(null))) {
67                      System.out.printf(
68                              "Not found in MessageDigestAlgorithms.values(): %s; note that SHAKE128_256 and SHAKE128_512 are only on Java 25 and up.%n", name);
69                      ok = false;
70                  }
71              }
72          }
73          if (!ok) {
74              // SHAKE128_256 and SHAKE128_512 are only in Java 25 and up.
75              fail("One or more entries are missing from the MessageDigestAlgorithms.values() array");
76          }
77          if (psf != MessageDigestAlgorithms.values().length) {
78              // SHAKE128_256 and SHAKE128_512 are only in Java 25 and up.
79              fail("One or more unexpected entries found in the MessageDigestAlgorithms.values() array");
80          }
81      }
82  
83      private static boolean contains(final String key) {
84          for (final String s : MessageDigestAlgorithms.values()) {
85              if (s.equals(key)) {
86                  return true;
87              }
88          }
89          return false;
90      }
91  
92      public static String[] data() {
93          return MessageDigestAlgorithms.values();
94      }
95  
96      private DigestUtilsTest digestUtilsTest;
97  
98      private byte[] digestTestData(final String messageDigestAlgorithm) {
99          return DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), getTestData());
100     }
101 
102     private byte[] getTestData() {
103         return digestUtilsTest.getTestData();
104     }
105 
106     private File getTestFile() {
107         return digestUtilsTest.getTestPath().toFile();
108     }
109 
110     private Path getTestPath() {
111         return digestUtilsTest.getTestPath();
112     }
113 
114     private RandomAccessFile getTestRandomAccessFile() {
115         return digestUtilsTest.getTestRandomAccessFile();
116     }
117 
118     @BeforeEach
119     public void setUp() throws Exception {
120         digestUtilsTest = new DigestUtilsTest();
121         digestUtilsTest.setUp();
122     }
123 
124     @AfterEach
125     public void tearDown() throws Exception {
126         digestUtilsTest.tearDown();
127         digestUtilsTest = null;
128     }
129 
130     @ParameterizedTest
131     @MethodSource("data")
132     void testAlgorithm(final String messageDigestAlgorithm) throws NoSuchAlgorithmException {
133         final String algorithm = messageDigestAlgorithm;
134         assertNotNull(algorithm);
135         assertFalse(algorithm.isEmpty());
136         assumeTrue(DigestUtils.isAvailable(messageDigestAlgorithm));
137         MessageDigest.getInstance(algorithm);
138     }
139 
140     @ParameterizedTest
141     @MethodSource("data")
142     void testDigestByteArray(final String messageDigestAlgorithm) {
143         assumeTrue(DigestUtils.isAvailable(messageDigestAlgorithm));
144         assertArrayEquals(digestTestData(messageDigestAlgorithm), DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), getTestData()));
145         assertArrayEquals(digestTestData(messageDigestAlgorithm), DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), getTestData()));
146     }
147 
148     @ParameterizedTest
149     @MethodSource("data")
150     void testDigestByteBuffer(final String messageDigestAlgorithm) {
151         assumeTrue(DigestUtils.isAvailable(messageDigestAlgorithm));
152         assertArrayEquals(digestTestData(messageDigestAlgorithm),
153                 DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), ByteBuffer.wrap(getTestData())));
154         assertArrayEquals(digestTestData(messageDigestAlgorithm),
155                 DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), ByteBuffer.wrap(getTestData())));
156     }
157 
158     @ParameterizedTest
159     @MethodSource("data")
160     void testDigestFile(final String messageDigestAlgorithm) throws IOException {
161         assumeTrue(DigestUtils.isAvailable(messageDigestAlgorithm));
162         assertArrayEquals(digestTestData(messageDigestAlgorithm), DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), getTestFile()));
163         assertArrayEquals(digestTestData(messageDigestAlgorithm), DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), getTestFile()));
164     }
165 
166     @ParameterizedTest
167     @MethodSource("data")
168     void testDigestInputStream(final String messageDigestAlgorithm) throws IOException {
169         assumeTrue(DigestUtils.isAvailable(messageDigestAlgorithm));
170         assertArrayEquals(digestTestData(messageDigestAlgorithm),
171                 DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), new ByteArrayInputStream(getTestData())));
172         assertArrayEquals(digestTestData(messageDigestAlgorithm),
173                 DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), new ByteArrayInputStream(getTestData())));
174     }
175 
176     private void testDigestPath(final String messageDigestAlgorithm, final OpenOption... options) throws IOException {
177         assumeTrue(DigestUtils.isAvailable(messageDigestAlgorithm));
178         assertArrayEquals(digestTestData(messageDigestAlgorithm), DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), getTestPath(), options));
179         assertArrayEquals(digestTestData(messageDigestAlgorithm), DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), getTestPath(), options));
180     }
181 
182     @ParameterizedTest
183     @MethodSource("data")
184     void testDigestPathOpenOptionsEmpty(final String messageDigestAlgorithm) throws IOException {
185         testDigestPath(messageDigestAlgorithm);
186     }
187 
188     @ParameterizedTest
189     @MethodSource("data")
190     void testDigestPathStandardOpenOptionRead(final String messageDigestAlgorithm) throws IOException {
191         testDigestPath(messageDigestAlgorithm, StandardOpenOption.READ);
192     }
193 
194     @ParameterizedTest
195     @MethodSource("data")
196     void testGetMessageDigest(final String messageDigestAlgorithm) {
197         assumeTrue(DigestUtils.isAvailable(messageDigestAlgorithm));
198         final MessageDigest messageDigest = DigestUtils.getDigest(messageDigestAlgorithm);
199         assertEquals(messageDigestAlgorithm, messageDigest.getAlgorithm());
200     }
201 
202     @ParameterizedTest
203     @MethodSource("data")
204     void testNonBlockingDigestRandomAccessFile(final String messageDigestAlgorithm) throws IOException {
205         assumeTrue(DigestUtils.isAvailable(messageDigestAlgorithm));
206 
207         final byte[] expected = digestTestData(messageDigestAlgorithm);
208 
209         @SuppressWarnings("resource") // test manages RAF
210         final RandomAccessFile randomAccessFile = getTestRandomAccessFile();
211         assertArrayEquals(expected, DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), randomAccessFile));
212         randomAccessFile.seek(0);
213         assertArrayEquals(expected, DigestUtils.digest(DigestUtils.getDigest(messageDigestAlgorithm), randomAccessFile));
214     }
215 
216 }