diff --git a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java index 59d8a9913..c9dedc8d7 100644 --- a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java +++ b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java @@ -31,7 +31,7 @@ import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySupport; -import org.eclipse.aether.util.ChecksumUtils; +import org.eclipse.aether.util.StringDigestUtil; import static java.util.stream.Collectors.toList; @@ -104,7 +104,7 @@ public void update(final ByteBuffer input) { @Override public String checksum() { - return ChecksumUtils.toHexString(messageDigest.digest()); + return StringDigestUtil.toHexString(messageDigest.digest()); } }; } catch (NoSuchAlgorithmException e) { diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java index d02f73701..12bd4797b 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultFileProcessor.java @@ -21,20 +21,13 @@ import javax.inject.Named; import javax.inject.Singleton; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UncheckedIOException; +import java.io.*; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import org.eclipse.aether.spi.io.FileProcessor; -import org.eclipse.aether.util.ChecksumUtils; import org.eclipse.aether.util.FileUtils; /** @@ -142,7 +135,34 @@ public void move(File source, File target) throws IOException { @Override public String readChecksum(final File checksumFile) throws IOException { // for now do exactly same as happened before, but FileProcessor is a component and can be replaced - return ChecksumUtils.read(checksumFile); + String checksum = ""; + try (BufferedReader br = new BufferedReader( + new InputStreamReader(Files.newInputStream(checksumFile.toPath()), StandardCharsets.UTF_8), 512)) { + while (true) { + String line = br.readLine(); + if (line == null) { + break; + } + line = line.trim(); + if (!line.isEmpty()) { + checksum = line; + break; + } + } + } + + if (checksum.matches(".+= [0-9A-Fa-f]+")) { + int lastSpacePos = checksum.lastIndexOf(' '); + checksum = checksum.substring(lastSpacePos + 1); + } else { + int spacePos = checksum.indexOf(' '); + + if (spacePos != -1) { + checksum = checksum.substring(0, spacePos); + } + } + + return checksum; } @Override diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/MessageDigestChecksumAlgorithmFactorySupport.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/MessageDigestChecksumAlgorithmFactorySupport.java index e335fec16..d704a4f5c 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/MessageDigestChecksumAlgorithmFactorySupport.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/MessageDigestChecksumAlgorithmFactorySupport.java @@ -25,7 +25,7 @@ import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithm; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySupport; -import org.eclipse.aether.util.ChecksumUtils; +import org.eclipse.aether.util.StringDigestUtil; /** * Support class to implement {@link ChecksumAlgorithmFactory} based on Java {@link MessageDigest}. @@ -49,7 +49,7 @@ public void update(final ByteBuffer input) { @Override public String checksum() { - return ChecksumUtils.toHexString(messageDigest.digest()); + return StringDigestUtil.toHexString(messageDigest.digest()); } }; } catch (NoSuchAlgorithmException e) { diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultFileProcessorTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultFileProcessorTest.java index 3c18d5d34..7de414b86 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultFileProcessorTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultFileProcessorTest.java @@ -134,4 +134,39 @@ void testWriteStream() throws IOException { target.delete(); } + + @Test + void testReadChecksumNonExistentFile() { + assertThrows(IOException.class, () -> fileProcessor.readChecksum(new File("non existent"))); + } + + @Test + void testReadChecksumEmptyFile() throws IOException { + File emptyFile = TestFileUtils.createTempFile(""); + String read = fileProcessor.readChecksum(emptyFile); + assertEquals("", read); + } + + @Test + void testReadChecksum() throws IOException { + String checksum = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; + File checksumFile = TestFileUtils.createTempFile(checksum); + String read = fileProcessor.readChecksum(checksumFile); + assertEquals(checksum, read); + } + + @Test + void testReadChecksumWhitespace() throws IOException { + String checksum = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; + File checksumFile; + String read; + + checksumFile = TestFileUtils.createTempFile("foobar(alg) = " + checksum); + read = fileProcessor.readChecksum(checksumFile); + assertEquals(checksum, read); + + checksumFile = TestFileUtils.createTempFile(checksum + " foobar"); + read = fileProcessor.readChecksum(checksumFile); + assertEquals(checksum, read); + } } diff --git a/maven-resolver-transport-http/pom.xml b/maven-resolver-transport-http/pom.xml index 2df00f96e..88f6feed3 100644 --- a/maven-resolver-transport-http/pom.xml +++ b/maven-resolver-transport-http/pom.xml @@ -105,6 +105,11 @@ maven-resolver-test-util test + + org.apache.maven.resolver + maven-resolver-impl + test + org.eclipse.jetty jetty-server diff --git a/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java b/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java index 74f3c9e24..b2880a4f0 100644 --- a/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java +++ b/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java @@ -37,7 +37,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.eclipse.aether.util.ChecksumUtils; +import org.eclipse.aether.internal.impl.checksum.Sha1ChecksumAlgorithmFactory; +import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmHelper; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.server.Request; @@ -334,12 +335,12 @@ public void handle(String target, Request req, HttpServletRequest request, HttpS "bytes " + offset + "-" + (file.length() - 1L) + "/" + file.length()); } if (checksumHeader != null) { - Map checksums = ChecksumUtils.calc(file, Collections.singleton("SHA-1")); + Map checksums = ChecksumAlgorithmHelper.calculate( + file, Collections.singletonList(new Sha1ChecksumAlgorithmFactory())); if (checksumHeader == ChecksumHeader.NEXUS) { response.setHeader(HttpHeader.ETAG.asString(), "{SHA1{" + checksums.get("SHA-1") + "}}"); } else if (checksumHeader == ChecksumHeader.XCHECKSUM) { - response.setHeader( - "x-checksum-sha1", checksums.get("SHA-1").toString()); + response.setHeader("x-checksum-sha1", checksums.get(Sha1ChecksumAlgorithmFactory.NAME)); } } if (HttpMethod.HEAD.is(req.getMethod())) { diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/ChecksumUtils.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/ChecksumUtils.java index d3acf2252..da1a597de 100644 --- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/ChecksumUtils.java +++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/ChecksumUtils.java @@ -34,7 +34,10 @@ /** * A utility class to assist in the verification and generation of checksums. + * + * @deprecated The use of class should be avoided, see {@link StringDigestUtil} and file processor in SPI module. */ +@Deprecated public final class ChecksumUtils { private ChecksumUtils() { @@ -147,21 +150,7 @@ private static Map calc(InputStream data, Collection alg */ @SuppressWarnings("checkstyle:magicnumber") public static String toHexString(byte[] bytes) { - if (bytes == null) { - return null; - } - - StringBuilder buffer = new StringBuilder(bytes.length * 2); - - for (byte aByte : bytes) { - int b = aByte & 0xFF; - if (b < 0x10) { - buffer.append('0'); - } - buffer.append(Integer.toHexString(b)); - } - - return buffer.toString(); + return StringDigestUtil.toHexString(bytes); } /** @@ -174,21 +163,6 @@ public static String toHexString(byte[] bytes) { */ @SuppressWarnings("checkstyle:magicnumber") public static byte[] fromHexString(String hexString) { - if (hexString == null) { - return null; - } - if (hexString.isEmpty()) { - return new byte[] {}; - } - int len = hexString.length(); - if (len % 2 != 0) { - throw new IllegalArgumentException("hexString length not even"); - } - byte[] data = new byte[len / 2]; - for (int i = 0; i < len; i += 2) { - data[i / 2] = (byte) - ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); - } - return data; + return StringDigestUtil.fromHexString(hexString); } } diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/StringDigestUtil.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/StringDigestUtil.java index 6f89246fe..91e8aae5a 100644 --- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/StringDigestUtil.java +++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/StringDigestUtil.java @@ -63,7 +63,7 @@ public StringDigestUtil update(String data) { * @see MessageDigest#digest() */ public String digest() { - return ChecksumUtils.toHexString(digest.digest()); + return toHexString(digest.digest()); } /** @@ -79,4 +79,59 @@ public static StringDigestUtil sha1() { public static String sha1(final String string) { return sha1().update(string).digest(); } + + /** + * Creates a hexadecimal representation of the specified bytes. Each byte is converted into a two-digit hex number + * and appended to the result with no separator between consecutive bytes. + * + * @param bytes The bytes to represent in hex notation, may be {@code null}. + * @return The hexadecimal representation of the input or {@code null} if the input was {@code null}. + * @since 2.0.0 + */ + @SuppressWarnings("checkstyle:magicnumber") + public static String toHexString(byte[] bytes) { + if (bytes == null) { + return null; + } + + StringBuilder buffer = new StringBuilder(bytes.length * 2); + + for (byte aByte : bytes) { + int b = aByte & 0xFF; + if (b < 0x10) { + buffer.append('0'); + } + buffer.append(Integer.toHexString(b)); + } + + return buffer.toString(); + } + + /** + * Creates a byte array out of hexadecimal representation of the specified bytes. If input string is {@code null}, + * {@code null} is returned. Input value must have even length (due hex encoding = 2 chars one byte). + * + * @param hexString The hexString to convert to byte array, may be {@code null}. + * @return The byte array of the input or {@code null} if the input was {@code null}. + * @since 2.0.0 + */ + @SuppressWarnings("checkstyle:magicnumber") + public static byte[] fromHexString(String hexString) { + if (hexString == null) { + return null; + } + if (hexString.isEmpty()) { + return new byte[] {}; + } + int len = hexString.length(); + if (len % 2 != 0) { + throw new IllegalArgumentException("hexString length not even"); + } + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) + ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); + } + return data; + } } diff --git a/maven-resolver-util/src/test/java/org/eclipse/aether/util/ChecksumUtilTest.java b/maven-resolver-util/src/test/java/org/eclipse/aether/util/ChecksumUtilTest.java deleted file mode 100644 index a00c9a620..000000000 --- a/maven-resolver-util/src/test/java/org/eclipse/aether/util/ChecksumUtilTest.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.eclipse.aether.util; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.eclipse.aether.internal.test.util.TestFileUtils.*; -import static org.junit.jupiter.api.Assertions.*; - -public class ChecksumUtilTest { - private static final String EMPTY = "EMPTY"; - private static final String PATTERN = "PATTERN"; - private static final String TEXT = "TEXT"; - - private final Map files = new HashMap<>(3); - - private final Map bytes = new HashMap<>(3); - - private static final Map emptyChecksums = new HashMap<>(); - - private static final Map patternChecksums = new HashMap<>(); - - private static final Map textChecksums = new HashMap<>(); - - private final Map> sums = new HashMap<>(); - - @BeforeAll - static void beforeClass() { - emptyChecksums.put("MD5", "d41d8cd98f00b204e9800998ecf8427e"); - emptyChecksums.put("SHA-1", "da39a3ee5e6b4b0d3255bfef95601890afd80709"); - emptyChecksums.put("SHA-256", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); - emptyChecksums.put( - "SHA-512", - "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"); - patternChecksums.put("MD5", "14f01d6c7de7d4cf0a4887baa3528b5a"); - patternChecksums.put("SHA-1", "feeeda19f626f9b0ef6cbf5948c1ec9531694295"); - patternChecksums.put("SHA-256", "81d480a714840ab206dc8de62ca6119036f65499ad9e2e227c2465551bed684d"); - patternChecksums.put( - "SHA-512", - "931aa34118d9a85b9514e0224046d736a5bd7e2b2f366505fe1ad07ed85e1a4ac0cbc18e9b9a7fe36ce835be2a18cb571202a4975d182553faff336970eb0b7e"); - textChecksums.put("MD5", "12582d1a662cefe3385f2113998e43ed"); - textChecksums.put("SHA-1", "a8ae272db549850eef2ff54376f8cac2770745ee"); - textChecksums.put("SHA-256", "35829adced2979761ba521dc2bb7d166e92ebed7342319d041398e509d481a46"); - textChecksums.put( - "SHA-512", - "2d6d19570b26080fa88101af2256ce3dae63512b06864cd36a05371c81d6dbd0ec226dd75f22e8d46a9582e1fc40ee6e7a02d43c852f3c92255982b835db6e7c"); - } - - @BeforeEach - void before() throws IOException { - sums.clear(); - - byte[] emptyBytes = new byte[0]; - bytes.put(EMPTY, emptyBytes); - files.put(EMPTY, createTempFile(emptyBytes, 0)); - sums.put(EMPTY, emptyChecksums); - - byte[] patternBytes = - writeBytes(new byte[] {0, 1, 2, 4, 8, 16, 32, 64, 127, -1, -2, -4, -8, -16, -32, -64, -127}, 1000); - bytes.put(PATTERN, patternBytes); - files.put(PATTERN, createTempFile(patternBytes, 1)); - sums.put(PATTERN, patternChecksums); - - byte[] textBytes = - writeBytes("the quick brown fox jumps over the lazy dog\n".getBytes(StandardCharsets.UTF_8), 500); - bytes.put(TEXT, textBytes); - files.put(TEXT, createTempFile(textBytes, 1)); - sums.put(TEXT, textChecksums); - } - - @Test - void testEquality() throws Throwable { - Map checksums; - - for (Map.Entry fileEntry : files.entrySet()) { - - checksums = ChecksumUtils.calc(fileEntry.getValue(), Arrays.asList("SHA-512", "SHA-256", "SHA-1", "MD5")); - - for (Entry entry : checksums.entrySet()) { - if (entry.getValue() instanceof Throwable) { - throw (Throwable) entry.getValue(); - } - String actual = entry.getValue().toString(); - String expected = sums.get(fileEntry.getKey()).get(entry.getKey()); - assertEquals( - expected, - actual, - String.format( - "checksums do not match for '%s', algorithm '%s'", - fileEntry.getValue().getName(), entry.getKey())); - } - assertTrue(fileEntry.getValue().delete(), "Could not delete file"); - } - } - - @Test - void testFileHandleLeakage() throws IOException { - for (File file : files.values()) { - for (int i = 0; i < 150; i++) { - ChecksumUtils.calc(file, Arrays.asList("SHA-512", "SHA-256", "SHA-1", "MD5")); - } - assertTrue(file.delete(), "Could not delete file"); - } - } - - @Test - void testRead() throws IOException { - for (Map checksums : sums.values()) { - String sha512 = checksums.get("SHA-512"); - String sha256 = checksums.get("SHA-256"); - String sha1 = checksums.get("SHA-1"); - String md5 = checksums.get("MD5"); - - File sha512File = createTempFile(sha512); - File sha256File = createTempFile(sha256); - File sha1File = createTempFile(sha1); - File md5File = createTempFile(md5); - - assertEquals(sha512, ChecksumUtils.read(sha512File)); - assertEquals(sha256, ChecksumUtils.read(sha256File)); - assertEquals(sha1, ChecksumUtils.read(sha1File)); - assertEquals(md5, ChecksumUtils.read(md5File)); - - assertTrue(sha512File.delete(), "ChecksumUtils leaks file handles (cannot delete checksums.sha512)"); - assertTrue(sha256File.delete(), "ChecksumUtils leaks file handles (cannot delete checksums.sha256)"); - assertTrue(sha1File.delete(), "ChecksumUtils leaks file handles (cannot delete checksums.sha1)"); - assertTrue(md5File.delete(), "ChecksumUtils leaks file handles (cannot delete checksums.md5)"); - } - } - - @Test - void testReadSpaces() throws IOException { - for (Map checksums : sums.values()) { - String sha512 = checksums.get("SHA-512"); - String sha256 = checksums.get("SHA-256"); - String sha1 = checksums.get("SHA-1"); - String md5 = checksums.get("MD5"); - - File sha512File = createTempFile("sha512-checksum = " + sha512); - File sha256File = createTempFile("sha256-checksum = " + sha256); - File sha1File = createTempFile("sha1-checksum = " + sha1); - File md5File = createTempFile(md5 + " test"); - - assertEquals(sha512, ChecksumUtils.read(sha512File)); - assertEquals(sha256, ChecksumUtils.read(sha256File)); - assertEquals(sha1, ChecksumUtils.read(sha1File)); - assertEquals(md5, ChecksumUtils.read(md5File)); - - assertTrue(sha512File.delete(), "ChecksumUtils leaks file handles (cannot delete checksums.sha512)"); - assertTrue(sha256File.delete(), "ChecksumUtils leaks file handles (cannot delete checksums.sha256)"); - assertTrue(sha1File.delete(), "ChecksumUtils leaks file handles (cannot delete checksums.sha1)"); - assertTrue(md5File.delete(), "ChecksumUtils leaks file handles (cannot delete checksums.md5)"); - } - } - - @Test - void testReadEmptyFile() throws IOException { - File file = createTempFile(""); - - assertEquals("", ChecksumUtils.read(file)); - - assertTrue(file.delete(), "ChecksumUtils leaks file handles (cannot delete checksum.empty)"); - } - - @Test - void testToHexString() { - assertNull(ChecksumUtils.toHexString(null)); - assertEquals("", ChecksumUtils.toHexString(new byte[] {})); - assertEquals("00", ChecksumUtils.toHexString(new byte[] {0})); - assertEquals("ff", ChecksumUtils.toHexString(new byte[] {-1})); - assertEquals("00017f", ChecksumUtils.toHexString(new byte[] {0, 1, 127})); - } - - @Test - void testFromHexString() { - assertNull(ChecksumUtils.toHexString(null)); - assertArrayEquals(new byte[] {}, ChecksumUtils.fromHexString("")); - assertArrayEquals(new byte[] {0}, ChecksumUtils.fromHexString("00")); - assertArrayEquals(new byte[] {-1}, ChecksumUtils.fromHexString("ff")); - assertArrayEquals(new byte[] {0, 1, 127}, ChecksumUtils.fromHexString("00017f")); - } - - @Test - void testCalcWithByteArray() throws Throwable { - Map checksums; - - for (Map.Entry bytesEntry : bytes.entrySet()) { - checksums = ChecksumUtils.calc(bytesEntry.getValue(), Arrays.asList("SHA-512", "SHA-256", "SHA-1", "MD5")); - - for (Entry entry : checksums.entrySet()) { - if (entry.getValue() instanceof Throwable) { - throw (Throwable) entry.getValue(); - } - String actual = entry.getValue().toString(); - String expected = sums.get(bytesEntry.getKey()).get(entry.getKey()); - assertEquals( - expected, - actual, - String.format( - "checksums do not match for '%s', algorithm '%s'", - bytesEntry.getKey(), entry.getKey())); - } - } - } - - private byte[] writeBytes(byte[] pattern, int repeat) { - byte[] result = new byte[pattern.length * repeat]; - for (int i = 0; i < repeat; i++) { - System.arraycopy(pattern, 0, result, i * pattern.length, pattern.length); - } - return result; - } -} diff --git a/maven-resolver-util/src/test/java/org/eclipse/aether/util/StringDigestUtilTest.java b/maven-resolver-util/src/test/java/org/eclipse/aether/util/StringDigestUtilTest.java index 595841583..3edae4e47 100644 --- a/maven-resolver-util/src/test/java/org/eclipse/aether/util/StringDigestUtilTest.java +++ b/maven-resolver-util/src/test/java/org/eclipse/aether/util/StringDigestUtilTest.java @@ -20,6 +20,8 @@ import org.junit.jupiter.api.Test; +import static org.eclipse.aether.util.StringDigestUtil.fromHexString; +import static org.eclipse.aether.util.StringDigestUtil.toHexString; import static org.junit.jupiter.api.Assertions.*; public class StringDigestUtilTest { @@ -73,4 +75,22 @@ void unsupportedAlg() { // good } } + + @Test + void testToHexString() { + assertNull(toHexString(null)); + assertEquals("", toHexString(new byte[] {})); + assertEquals("00", toHexString(new byte[] {0})); + assertEquals("ff", toHexString(new byte[] {-1})); + assertEquals("00017f", toHexString(new byte[] {0, 1, 127})); + } + + @Test + void testFromHexString() { + assertNull(fromHexString(null)); + assertArrayEquals(new byte[] {}, fromHexString("")); + assertArrayEquals(new byte[] {0}, fromHexString("00")); + assertArrayEquals(new byte[] {-1}, fromHexString("ff")); + assertArrayEquals(new byte[] {0, 1, 127}, fromHexString("00017f")); + } }