diff --git a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java index 359bd5e93daeb..4f0becc8ad5d8 100644 --- a/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java +++ b/core/tests/coretests/src/com/android/internal/util/HexDumpTest.java @@ -16,8 +16,16 @@ package com.android.internal.util; +import static com.android.internal.util.HexDump.hexStringToByteArray; +import static com.android.internal.util.HexDump.toHexString; + import junit.framework.TestCase; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.Random; + public final class HexDumpTest extends TestCase { public void testBytesToHexString() { assertEquals("abcdef", HexDump.toHexString( @@ -25,7 +33,142 @@ public final class HexDumpTest extends TestCase { assertEquals("ABCDEF", HexDump.toHexString( new byte[] { (byte) 0xab, (byte) 0xcd, (byte) 0xef }, true)); } - public void testNullArray() { - assertEquals("(null)", HexDump.toHexString(null)); + + public void testNullByteArray() { + assertThrows( + NullPointerException.class, + () -> HexDump.toHexString(null)); } + + public void testBytesToHexString_allByteValues() { + byte[] bytes = new byte[256]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = (byte) (i % 256); + } + + StringBuilder sb = new StringBuilder(); + for (char firstChar : "0123456789ABCDEF".toCharArray()) { + for (char secondChar : "0123456789ABCDEF".toCharArray()) { + sb.append(firstChar).append(secondChar); + } + } + String expected = sb.toString(); + + assertEquals(expected, HexDump.toHexString(bytes)); + } + + public void testRoundTrip_fromBytes() { + Random deterministicRandom = new Random(31337); // arbitrary but deterministic + for (int length = 0; length < 100; length++) { + byte[] bytes = new byte[length]; + deterministicRandom.nextBytes(bytes); + byte[] reconstruction = hexStringToByteArray(toHexString(bytes)); + + assertBytesEqual(bytes, reconstruction); + } + } + + public void testRoundTrip_fromString() { + String hexString = "0123456789ABCDEF72f9a3438934c378d34f32a8b932"; + for (int length = 0; length < hexString.length(); length += 2) { + String original = hexString.substring(0, length); + String reconstruction = toHexString(hexStringToByteArray(original)); + assertEquals(original.toUpperCase(), reconstruction); + } + } + + public void testToHexString_offsetLength() { + byte[] bytes = new byte[32]; + for (int i = 0; i < 16; i++) { + bytes[i] = (byte) i; + bytes[16 + i] = (byte) (16 * i); + } + String expected = "000102030405060708090A0B0C0D0E0F00102030405060708090A0B0C0D0E0F0"; + for (int offset = 0; offset < bytes.length; offset++) { + for (int len = 0; len < (bytes.length - offset); len++) { + + byte[] subBytes = new byte[len]; + System.arraycopy(bytes, offset, subBytes, 0, len); + + String actual = toHexString(bytes, offset, len); + assertEquals(expected.substring(2 * offset, 2 * offset + 2 * len), actual); + assertEquals(toHexString(subBytes), actual); + } + } + } + + public void testToHexString_case() { + byte[] bytes = new byte[32]; + for (int i = 0; i < 16; i++) { + bytes[i] = (byte) i; + bytes[16 + i] = (byte) (16 * i); + } + + String expected = "000102030405060708090A0B0C0D0E0F00102030405060708090A0B0C0D0E0F0"; + + assertEquals(expected.toUpperCase(), toHexString(bytes, true)); + assertEquals(expected.toLowerCase(), toHexString(bytes, false)); + + // default is uppercase + assertEquals(expected.toUpperCase(), toHexString(bytes)); + } + + public void testHexStringToByteArray_empty() { + assertBytesEqual(new byte[0], HexDump.hexStringToByteArray("")); + } + + public void testHexStringToByteArray_null() { + assertThrows( + NullPointerException.class, + () -> HexDump.hexStringToByteArray((String) null)); + } + + public void testHexStringToByteArray_invalidCharacters() { + // IllegalArgumentException would probably have been better than RuntimeException, but it + // might be too late to change now. + assertThrows( + RuntimeException.class, + () -> HexDump.hexStringToByteArray("GG")); + assertThrows( + RuntimeException.class, + () -> HexDump.hexStringToByteArray("\0\0")); + assertThrows( + RuntimeException.class, + () -> HexDump.hexStringToByteArray("abcdefgh")); + } + + public void testHexStringToByteArray_oddLength() { + // IllegalArgumentException would probably have been better than + // StringIndexOutOfBoundsException, but it might be too late to change now. + assertThrows( + StringIndexOutOfBoundsException.class, + () -> HexDump.hexStringToByteArray("A")); + assertThrows( + StringIndexOutOfBoundsException.class, + () -> HexDump.hexStringToByteArray("123")); + assertThrows( + StringIndexOutOfBoundsException.class, + () -> HexDump.hexStringToByteArray("ABCDE")); + } + + private static void assertBytesEqual(byte[] expected, byte[] actual) { + if (!Arrays.equals(expected, actual)) { + fail("Expected " + Arrays.toString(expected) + ", got " + Arrays.toString(actual)); + } + } + + private static void assertThrows(Class clazz, Runnable runnable) { + try { + runnable.run(); + } catch (RuntimeException exception) { + assertEquals(toStrackTrace(exception), clazz, exception.getClass()); + } + } + + private static String toStrackTrace(Throwable throwable) { + StringWriter stringWriter = new StringWriter(); + throwable.printStackTrace(new PrintWriter(stringWriter)); + return stringWriter.toString(); + } + }