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   *   http://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  package org.eclipse.aether.util;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.nio.charset.StandardCharsets;
24  import java.util.Arrays;
25  import java.util.HashMap;
26  import java.util.Map;
27  import java.util.Map.Entry;
28  
29  import org.junit.Before;
30  import org.junit.BeforeClass;
31  import org.junit.Test;
32  
33  import static org.eclipse.aether.internal.test.util.TestFileUtils.*;
34  import static org.junit.Assert.*;
35  
36  public class ChecksumUtilTest {
37      private static final String EMPTY = "EMPTY";
38      private static final String PATTERN = "PATTERN";
39      private static final String TEXT = "TEXT";
40  
41      private Map<String, File> files = new HashMap<>(3);
42  
43      private Map<String, byte[]> bytes = new HashMap<>(3);
44  
45      private static Map<String, String> emptyChecksums = new HashMap<>();
46  
47      private static Map<String, String> patternChecksums = new HashMap<>();
48  
49      private static Map<String, String> textChecksums = new HashMap<>();
50  
51      private Map<String, Map<String, String>> sums = new HashMap<>();
52  
53      @BeforeClass
54      public static void beforeClass() {
55          emptyChecksums.put("MD5", "d41d8cd98f00b204e9800998ecf8427e");
56          emptyChecksums.put("SHA-1", "da39a3ee5e6b4b0d3255bfef95601890afd80709");
57          emptyChecksums.put("SHA-256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
58          emptyChecksums.put(
59                  "SHA-512",
60                  "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
61          patternChecksums.put("MD5", "14f01d6c7de7d4cf0a4887baa3528b5a");
62          patternChecksums.put("SHA-1", "feeeda19f626f9b0ef6cbf5948c1ec9531694295");
63          patternChecksums.put("SHA-256", "81d480a714840ab206dc8de62ca6119036f65499ad9e2e227c2465551bed684d");
64          patternChecksums.put(
65                  "SHA-512",
66                  "931aa34118d9a85b9514e0224046d736a5bd7e2b2f366505fe1ad07ed85e1a4ac0cbc18e9b9a7fe36ce835be2a18cb571202a4975d182553faff336970eb0b7e");
67          textChecksums.put("MD5", "12582d1a662cefe3385f2113998e43ed");
68          textChecksums.put("SHA-1", "a8ae272db549850eef2ff54376f8cac2770745ee");
69          textChecksums.put("SHA-256", "35829adced2979761ba521dc2bb7d166e92ebed7342319d041398e509d481a46");
70          textChecksums.put(
71                  "SHA-512",
72                  "2d6d19570b26080fa88101af2256ce3dae63512b06864cd36a05371c81d6dbd0ec226dd75f22e8d46a9582e1fc40ee6e7a02d43c852f3c92255982b835db6e7c");
73      }
74  
75      @Before
76      public void before() throws IOException {
77          sums.clear();
78  
79          byte[] emptyBytes = new byte[0];
80          bytes.put(EMPTY, emptyBytes);
81          files.put(EMPTY, createTempFile(emptyBytes, 0));
82          sums.put(EMPTY, emptyChecksums);
83  
84          byte[] patternBytes =
85                  writeBytes(new byte[] {0, 1, 2, 4, 8, 16, 32, 64, 127, -1, -2, -4, -8, -16, -32, -64, -127}, 1000);
86          bytes.put(PATTERN, patternBytes);
87          files.put(PATTERN, createTempFile(patternBytes, 1));
88          sums.put(PATTERN, patternChecksums);
89  
90          byte[] textBytes =
91                  writeBytes("the quick brown fox jumps over the lazy dog\n".getBytes(StandardCharsets.UTF_8), 500);
92          bytes.put(TEXT, textBytes);
93          files.put(TEXT, createTempFile(textBytes, 1));
94          sums.put(TEXT, textChecksums);
95      }
96  
97      @Test
98      public void testEquality() throws Throwable {
99          Map<String, Object> checksums = null;
100 
101         for (Map.Entry<String, File> fileEntry : files.entrySet()) {
102 
103             checksums = ChecksumUtils.calc(fileEntry.getValue(), Arrays.asList("SHA-512", "SHA-256", "SHA-1", "MD5"));
104 
105             for (Entry<String, Object> entry : checksums.entrySet()) {
106                 if (entry.getValue() instanceof Throwable) {
107                     throw (Throwable) entry.getValue();
108                 }
109                 String actual = entry.getValue().toString();
110                 String expected = sums.get(fileEntry.getKey()).get(entry.getKey());
111                 assertEquals(
112                         String.format(
113                                 "checksums do not match for '%s', algorithm '%s'",
114                                 fileEntry.getValue().getName(), entry.getKey()),
115                         expected,
116                         actual);
117             }
118             assertTrue("Could not delete file", fileEntry.getValue().delete());
119         }
120     }
121 
122     @Test
123     public void testFileHandleLeakage() throws IOException {
124         for (File file : files.values()) {
125             for (int i = 0; i < 150; i++) {
126                 ChecksumUtils.calc(file, Arrays.asList("SHA-512", "SHA-256", "SHA-1", "MD5"));
127             }
128             assertTrue("Could not delete file", file.delete());
129         }
130     }
131 
132     @Test
133     public void testRead() throws IOException {
134         for (Map<String, String> checksums : sums.values()) {
135             String sha512 = checksums.get("SHA-512");
136             String sha256 = checksums.get("SHA-256");
137             String sha1 = checksums.get("SHA-1");
138             String md5 = checksums.get("MD5");
139 
140             File sha512File = createTempFile(sha512);
141             File sha256File = createTempFile(sha256);
142             File sha1File = createTempFile(sha1);
143             File md5File = createTempFile(md5);
144 
145             assertEquals(sha512, ChecksumUtils.read(sha512File));
146             assertEquals(sha256, ChecksumUtils.read(sha256File));
147             assertEquals(sha1, ChecksumUtils.read(sha1File));
148             assertEquals(md5, ChecksumUtils.read(md5File));
149 
150             assertTrue("ChecksumUtils leaks file handles (cannot delete checksums.sha512)", sha512File.delete());
151             assertTrue("ChecksumUtils leaks file handles (cannot delete checksums.sha256)", sha256File.delete());
152             assertTrue("ChecksumUtils leaks file handles (cannot delete checksums.sha1)", sha1File.delete());
153             assertTrue("ChecksumUtils leaks file handles (cannot delete checksums.md5)", md5File.delete());
154         }
155     }
156 
157     @Test
158     public void testReadSpaces() throws IOException {
159         for (Map<String, String> checksums : sums.values()) {
160             String sha512 = checksums.get("SHA-512");
161             String sha256 = checksums.get("SHA-256");
162             String sha1 = checksums.get("SHA-1");
163             String md5 = checksums.get("MD5");
164 
165             File sha512File = createTempFile("sha512-checksum = " + sha512);
166             File sha256File = createTempFile("sha256-checksum = " + sha256);
167             File sha1File = createTempFile("sha1-checksum = " + sha1);
168             File md5File = createTempFile(md5 + " test");
169 
170             assertEquals(sha512, ChecksumUtils.read(sha512File));
171             assertEquals(sha256, ChecksumUtils.read(sha256File));
172             assertEquals(sha1, ChecksumUtils.read(sha1File));
173             assertEquals(md5, ChecksumUtils.read(md5File));
174 
175             assertTrue("ChecksumUtils leaks file handles (cannot delete checksums.sha512)", sha512File.delete());
176             assertTrue("ChecksumUtils leaks file handles (cannot delete checksums.sha256)", sha256File.delete());
177             assertTrue("ChecksumUtils leaks file handles (cannot delete checksums.sha1)", sha1File.delete());
178             assertTrue("ChecksumUtils leaks file handles (cannot delete checksums.md5)", md5File.delete());
179         }
180     }
181 
182     @Test
183     public void testReadEmptyFile() throws IOException {
184         File file = createTempFile("");
185 
186         assertEquals("", ChecksumUtils.read(file));
187 
188         assertTrue("ChecksumUtils leaks file handles (cannot delete checksum.empty)", file.delete());
189     }
190 
191     @Test
192     public void testToHexString() {
193         assertNull(ChecksumUtils.toHexString(null));
194         assertEquals("", ChecksumUtils.toHexString(new byte[] {}));
195         assertEquals("00", ChecksumUtils.toHexString(new byte[] {0}));
196         assertEquals("ff", ChecksumUtils.toHexString(new byte[] {-1}));
197         assertEquals("00017f", ChecksumUtils.toHexString(new byte[] {0, 1, 127}));
198     }
199 
200     @Test
201     public void testFromHexString() {
202         assertNull(ChecksumUtils.toHexString(null));
203         assertArrayEquals(new byte[] {}, ChecksumUtils.fromHexString(""));
204         assertArrayEquals(new byte[] {0}, ChecksumUtils.fromHexString("00"));
205         assertArrayEquals(new byte[] {-1}, ChecksumUtils.fromHexString("ff"));
206         assertArrayEquals(new byte[] {0, 1, 127}, ChecksumUtils.fromHexString("00017f"));
207     }
208 
209     @Test
210     public void testCalcWithByteArray() throws Throwable {
211         Map<String, Object> checksums = null;
212 
213         for (Map.Entry<String, byte[]> bytesEntry : bytes.entrySet()) {
214             checksums = ChecksumUtils.calc(bytesEntry.getValue(), Arrays.asList("SHA-512", "SHA-256", "SHA-1", "MD5"));
215 
216             for (Entry<String, Object> entry : checksums.entrySet()) {
217                 if (entry.getValue() instanceof Throwable) {
218                     throw (Throwable) entry.getValue();
219                 }
220                 String actual = entry.getValue().toString();
221                 String expected = sums.get(bytesEntry.getKey()).get(entry.getKey());
222                 assertEquals(
223                         String.format(
224                                 "checksums do not match for '%s', algorithm '%s'", bytesEntry.getKey(), entry.getKey()),
225                         expected,
226                         actual);
227             }
228         }
229     }
230 
231     private byte[] writeBytes(byte[] pattern, int repeat) {
232         byte[] result = new byte[pattern.length * repeat];
233         for (int i = 0; i < repeat; i++) {
234             System.arraycopy(pattern, 0, result, i * pattern.length, pattern.length);
235         }
236         return result;
237     }
238 }