Merge changes I485e0bbc,I640f343d am: a95cfa14f9 am: 19fe87589b
Original change: https://android-review.googlesource.com/c/platform/frameworks/libs/net/+/1536721
MUST ONLY BE SUBMITTED BY AUTOMERGER
Change-Id: Ic48799470ce7b33d330ad4d94a31d15618739b21
diff --git a/staticlibs/device/com/android/net/module/util/HexDump.java b/staticlibs/device/com/android/net/module/util/HexDump.java
new file mode 100644
index 0000000..d8c0fb5
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/HexDump.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed 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 com.android.net.module.util;
+
+import android.annotation.Nullable;
+
+/**
+ * Hex utility functions.
+ *
+ * A copy from frameworks/base/core/java/com/android/internal/util/HexDump.java, to be shared
+ * by multiple modules.
+ */
+public class HexDump {
+ private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F' };
+ private static final char[] HEX_LOWER_CASE_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ /**
+ * Dump the hex string corresponding to the specified byte array.
+ *
+ * @param array byte array to be dumped.
+ */
+ public static String dumpHexString(@Nullable byte[] array) {
+ if (array == null) return "(null)";
+ return dumpHexString(array, 0, array.length);
+ }
+
+ /**
+ * Dump the hex string corresponding to the specified byte array.
+ *
+ * @param array byte array to be dumped.
+ * @param offset the offset in array where dump should start.
+ * @param length the length of bytes to be dumped.
+ */
+ public static String dumpHexString(@Nullable byte[] array, int offset, int length) {
+ if (array == null) return "(null)";
+ StringBuilder result = new StringBuilder();
+
+ byte[] line = new byte[16];
+ int lineIndex = 0;
+
+ result.append("\n0x");
+ result.append(toHexString(offset));
+
+ for (int i = offset; i < offset + length; i++) {
+ if (lineIndex == 16) {
+ result.append(" ");
+
+ for (int j = 0; j < 16; j++) {
+ if (line[j] > ' ' && line[j] < '~') {
+ result.append(new String(line, j, 1));
+ } else {
+ result.append(".");
+ }
+ }
+
+ result.append("\n0x");
+ result.append(toHexString(i));
+ lineIndex = 0;
+ }
+
+ byte b = array[i];
+ result.append(" ");
+ result.append(HEX_DIGITS[(b >>> 4) & 0x0F]);
+ result.append(HEX_DIGITS[b & 0x0F]);
+
+ line[lineIndex++] = b;
+ }
+
+ if (lineIndex != 16) {
+ int count = (16 - lineIndex) * 3;
+ count++;
+ for (int i = 0; i < count; i++) {
+ result.append(" ");
+ }
+
+ for (int i = 0; i < lineIndex; i++) {
+ if (line[i] > ' ' && line[i] < '~') {
+ result.append(new String(line, i, 1));
+ } else {
+ result.append(".");
+ }
+ }
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Convert a byte to an uppercase hex string.
+ *
+ * @param b the byte to be converted.
+ */
+ public static String toHexString(byte b) {
+ return toHexString(toByteArray(b));
+ }
+
+ /**
+ * Convert a byte array to an uppercase hex string.
+ *
+ * @param array the byte array to be converted.
+ */
+ public static String toHexString(byte[] array) {
+ return toHexString(array, 0, array.length, true);
+ }
+
+ /**
+ * Convert a byte array to a hex string.
+ *
+ * @param array the byte array to be converted.
+ * @param upperCase whether the converted hex string should be uppercase or not.
+ */
+ public static String toHexString(byte[] array, boolean upperCase) {
+ return toHexString(array, 0, array.length, upperCase);
+ }
+
+ /**
+ * Convert a byte array to hex string.
+ *
+ * @param array the byte array to be converted.
+ * @param offset the offset in array where conversion should start.
+ * @param length the length of bytes to be converted.
+ */
+ public static String toHexString(byte[] array, int offset, int length) {
+ return toHexString(array, offset, length, true);
+ }
+
+ /**
+ * Convert a byte array to hex string.
+ *
+ * @param array the byte array to be converted.
+ * @param offset the offset in array where conversion should start.
+ * @param length the length of bytes to be converted.
+ * @param upperCase whether the converted hex string should be uppercase or not.
+ */
+ public static String toHexString(byte[] array, int offset, int length, boolean upperCase) {
+ char[] digits = upperCase ? HEX_DIGITS : HEX_LOWER_CASE_DIGITS;
+ char[] buf = new char[length * 2];
+
+ int bufIndex = 0;
+ for (int i = offset; i < offset + length; i++) {
+ byte b = array[i];
+ buf[bufIndex++] = digits[(b >>> 4) & 0x0F];
+ buf[bufIndex++] = digits[b & 0x0F];
+ }
+
+ return new String(buf);
+ }
+
+ /**
+ * Convert an integer to hex string.
+ *
+ * @param i the integer to be converted.
+ */
+ public static String toHexString(int i) {
+ return toHexString(toByteArray(i));
+ }
+
+ /**
+ * Convert a byte to byte array.
+ *
+ * @param b the byte to be converted.
+ */
+ public static byte[] toByteArray(byte b) {
+ byte[] array = new byte[1];
+ array[0] = b;
+ return array;
+ }
+
+ /**
+ * Convert an integer to byte array.
+ *
+ * @param i the integer to be converted.
+ */
+ public static byte[] toByteArray(int i) {
+ byte[] array = new byte[4];
+
+ array[3] = (byte) (i & 0xFF);
+ array[2] = (byte) ((i >> 8) & 0xFF);
+ array[1] = (byte) ((i >> 16) & 0xFF);
+ array[0] = (byte) ((i >> 24) & 0xFF);
+
+ return array;
+ }
+
+ private static int toByte(char c) {
+ if (c >= '0' && c <= '9') return (c - '0');
+ if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
+ if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
+
+ throw new RuntimeException("Invalid hex char '" + c + "'");
+ }
+
+ /**
+ * Convert a hex string to a byte array.
+ *
+ * @param hexString the string to be converted.
+ */
+ public static byte[] hexStringToByteArray(String hexString) {
+ int length = hexString.length();
+ byte[] buffer = new byte[length / 2];
+
+ for (int i = 0; i < length; i += 2) {
+ buffer[i / 2] =
+ (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1)));
+ }
+
+ return buffer;
+ }
+
+ /**
+ * Convert a byte to hex string and append it to StringBuilder.
+ *
+ * @param sb StringBuilder instance.
+ * @param b the byte to be converted.
+ * @param upperCase whether the converted hex string should be uppercase or not.
+ */
+ public static StringBuilder appendByteAsHex(StringBuilder sb, byte b, boolean upperCase) {
+ char[] digits = upperCase ? HEX_DIGITS : HEX_LOWER_CASE_DIGITS;
+ sb.append(digits[(b >> 4) & 0xf]);
+ sb.append(digits[b & 0xf]);
+ return sb;
+ }
+}
diff --git a/staticlibs/device/com/android/net/module/util/Struct.java b/staticlibs/device/com/android/net/module/util/Struct.java
index 07a7e7a..afc2e64 100644
--- a/staticlibs/device/com/android/net/module/util/Struct.java
+++ b/staticlibs/device/com/android/net/module/util/Struct.java
@@ -30,6 +30,8 @@
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -111,7 +113,7 @@
UBE63, // unsigned long(MSB: 0) in network order, size = 8 bytes
UBE64, // unsigned long in network order, size = 8 bytes
ByteArray, // byte array with predefined length
- EUI48, // a 48-bits long MAC address
+ EUI48, // IEEE Extended Unique Identifier, a 48-bits long MAC address in network order
}
/**
@@ -607,4 +609,75 @@
public final byte[] writeToBytes() {
return writeToBytes(ByteOrder.nativeOrder());
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || this.getClass() != obj.getClass()) return false;
+
+ final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass());
+ for (int i = 0; i < fieldInfos.length; i++) {
+ try {
+ final Object value = fieldInfos[i].field.get(this);
+ final Object otherValue = fieldInfos[i].field.get(obj);
+
+ // Use Objects#deepEquals because the equals method on arrays does not check the
+ // contents of the array. The only difference between Objects#deepEquals and
+ // Objects#equals is that the former will call Arrays#deepEquals when comparing
+ // arrays. In turn, the only difference between Arrays#deepEquals is that it
+ // supports nested arrays. Struct does not currently support these, and if it did,
+ // Objects#deepEquals might be more correct.
+ if (!Objects.deepEquals(value, otherValue)) return false;
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Cannot access field: " + fieldInfos[i].field, e);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass());
+ final Object[] values = new Object[fieldInfos.length];
+ for (int i = 0; i < fieldInfos.length; i++) {
+ final Object value;
+ try {
+ value = fieldInfos[i].field.get(this);
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Cannot access field: " + fieldInfos[i].field, e);
+ }
+ // For byte array field, put the hash code generated based on the array content into
+ // the Object array instead of the reference to byte array, which might change and cause
+ // to get a different hash code even with the exact same elements.
+ if (fieldInfos[i].field.getType() == byte[].class) {
+ values[i] = Arrays.hashCode((byte[]) value);
+ } else {
+ values[i] = value;
+ }
+ }
+ return Objects.hash(values);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass());
+ for (int i = 0; i < fieldInfos.length; i++) {
+ sb.append(fieldInfos[i].field.getName()).append(": ");
+ final Object value;
+ try {
+ value = fieldInfos[i].field.get(this);
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException("Cannot access field: " + fieldInfos[i].field, e);
+ }
+ if (value == null) {
+ sb.append("null");
+ } else if (fieldInfos[i].field.getType() == byte[].class) {
+ sb.append("0x").append(HexDump.toHexString((byte[]) value));
+ } else {
+ sb.append(value.toString());
+ }
+ if (i != fieldInfos.length - 1) sb.append(", ");
+ }
+ return sb.toString();
+ }
}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java
new file mode 100644
index 0000000..7e6c7e2
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/HexDumpTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed 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 com.android.net.module.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class HexDumpTest {
+ @Test
+ public void testBytesToHexString() {
+ assertEquals("abcdef", HexDump.toHexString(
+ new byte[]{(byte) 0xab, (byte) 0xcd, (byte) 0xef}, false));
+ assertEquals("ABCDEF", HexDump.toHexString(
+ new byte[]{(byte) 0xab, (byte) 0xcd, (byte) 0xef}, true));
+ }
+
+ @Test
+ public void testNullArray() {
+ assertEquals("(null)", HexDump.dumpHexString(null));
+ }
+
+ @Test
+ public void testHexStringToBytes() {
+ assertArrayEquals(new byte[]{(byte) 0xab, (byte) 0xcd, (byte) 0xef},
+ HexDump.hexStringToByteArray("abcdef"));
+ assertArrayEquals(new byte[]{(byte) 0xAB, (byte) 0xCD, (byte) 0xEF},
+ HexDump.hexStringToByteArray("ABCDEF"));
+ }
+
+ @Test
+ public void testIntegerToBytes() {
+ assertArrayEquals(new byte[]{(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x04},
+ HexDump.toByteArray((int) 0xff000004));
+ }
+
+ @Test
+ public void testByteToBytes() {
+ assertArrayEquals(new byte[]{(byte) 0x7f}, HexDump.toByteArray((byte) 0x7f));
+ }
+
+ @Test
+ public void testIntegerToHexString() {
+ assertEquals("FF000004", HexDump.toHexString((int) 0xff000004));
+ }
+
+ @Test
+ public void testByteToHexString() {
+ assertEquals("7F", HexDump.toHexString((byte) 0x7f));
+ }
+}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java
index d5e27fb..253b911 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/StructTest.java
@@ -20,6 +20,8 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import android.net.IpPrefix;
@@ -67,6 +69,10 @@
// PREF64 option, 2001:db8:3:4:5:6::/96, lifetime: 10064
private static final String OPT_PREF64 = "2750" + "20010db80003000400050006";
+ private static final byte[] TEST_PREFIX64 = new byte[]{
+ (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x00, (byte) 0x03,
+ (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06,
+ };
private <T> T doParsingMessageTest(final String hexString, final Class<T> clazz,
final ByteOrder order) {
@@ -699,7 +705,7 @@
}
@Test
- public void testStructToByteArray() {
+ public void testStructToByteArrayRoundTrip() {
final SignedDataMessage littleEndianMsg = doParsingMessageTest(SIGNED_DATA,
SignedDataMessage.class, ByteOrder.LITTLE_ENDIAN);
assertArrayEquals(toByteBuffer(SIGNED_DATA).array(),
@@ -714,6 +720,229 @@
ByteOrder.LITTLE_ENDIAN) ? littleEndianMsg : bigEndianMsg;
assertArrayEquals(toByteBuffer(SIGNED_DATA).array(),
nativeOrderMsg.writeToBytes());
+ }
+ @Test
+ public void testStructToByteArray() {
+ final SignedDataMessage msg = new SignedDataMessage((byte) -5, (short) 42, (int) 0xff000004,
+ (long) 0xff000004ff000005L);
+ final String leHexString = "fb" + "2a00" + "040000ff" + "050000ff040000ff";
+ final String beHexString = "fb" + "002a" + "ff000004" + "ff000004ff000005";
+ final String hexString = ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)
+ ? leHexString : beHexString;
+ assertArrayEquals(toByteBuffer(hexString).array(), msg.writeToBytes());
+ }
+
+ static class FullTypeMessage extends Struct {
+ @Field(order = 0, type = Type.U8) public final short u8;
+ @Field(order = 1, type = Type.U16) public final int u16;
+ @Field(order = 2, type = Type.U32) public final long u32;
+ @Field(order = 3, type = Type.U63) public final long u63;
+ @Field(order = 4, type = Type.U64) public final BigInteger u64;
+ @Field(order = 5, type = Type.S8) public final byte s8;
+ @Field(order = 6, type = Type.S16) public final short s16;
+ @Field(order = 7, type = Type.S32) public final int s32;
+ @Field(order = 8, type = Type.S64) public final long s64;
+ @Field(order = 9, type = Type.UBE16) public final int ube16;
+ @Field(order = 10, type = Type.UBE32) public final long ube32;
+ @Field(order = 11, type = Type.UBE63) public final long ube63;
+ @Field(order = 12, type = Type.UBE64) public final BigInteger ube64;
+ @Field(order = 13, type = Type.ByteArray, arraysize = 12) public final byte[] bytes;
+ @Field(order = 14, type = Type.EUI48) public final MacAddress eui48;
+
+ FullTypeMessage(final short u8, final int u16, final long u32, final long u63,
+ final BigInteger u64, final byte s8, final short s16, final int s32, final long s64,
+ final int ube16, final long ube32, final long ube63, final BigInteger ube64,
+ final byte[] bytes, final MacAddress eui48) {
+ this.u8 = u8;
+ this.u16 = u16;
+ this.u32 = u32;
+ this.u63 = u63;
+ this.u64 = u64;
+ this.s8 = s8;
+ this.s16 = s16;
+ this.s32 = s32;
+ this.s64 = s64;
+ this.ube16 = ube16;
+ this.ube32 = ube32;
+ this.ube63 = ube63;
+ this.ube64 = ube64;
+ this.bytes = bytes;
+ this.eui48 = eui48;
+ }
+ }
+
+ private static final String FULL_TYPE_DATA = "ff" + "ffff" + "ffffffff" + "7fffffffffffffff"
+ + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff" + "7fffffffffffffff" + "7fff"
+ + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff" + "20010db80003000400050006"
+ + "001122334455";
+ private static final String FULL_TYPE_DATA_DIFF_MAC = "ff" + "ffff" + "ffffffff"
+ + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff"
+ + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff"
+ + "20010db80003000400050006" + "112233445566";
+ private static final String FULL_TYPE_DATA_DIFF_LONG = "ff" + "ffff" + "ffffffff"
+ + "7ffffffffffffffe" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff"
+ + "7fffffffffffffff" + "7fff" + "7fffffff" + "7fffffffffffffff" + "ffffffffffffffff"
+ + "20010db80003000400050006" + "001122334455";
+ private static final String FULL_TYPE_DATA_DIFF_INTEGER = "ff" + "ffff" + "ffffffff"
+ + "7fffffffffffffff" + "ffffffffffffffff" + "7f" + "7fff" + "7fffffff"
+ + "7fffffffffffffff" + "7fff" + "ffffff7f" + "7fffffffffffffff" + "ffffffffffffffff"
+ + "20010db80003000400050006" + "001122334455";
+ @Test
+ public void testStructClass_equals() {
+ final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class,
+ ByteOrder.BIG_ENDIAN);
+
+ assertEquals(255, msg.u8);
+ assertEquals(65535, msg.u16);
+ assertEquals(4294967295L, msg.u32);
+ assertEquals(9223372036854775807L, msg.u63);
+ assertEquals(new BigInteger("18446744073709551615"), msg.u64);
+ assertEquals(127, msg.s8);
+ assertEquals(32767, msg.s16);
+ assertEquals(2147483647, msg.s32);
+ assertEquals(9223372036854775807L, msg.s64);
+ assertEquals(32767, msg.ube16);
+ assertEquals(2147483647, msg.ube32);
+ assertEquals(9223372036854775807L, msg.ube63);
+ assertEquals(new BigInteger("18446744073709551615"), msg.ube64);
+ assertArrayEquals(TEST_PREFIX64, msg.bytes);
+ assertEquals(MacAddress.fromString("00:11:22:33:44:55"), msg.eui48);
+
+ assertEquals(78, msg.getSize(FullTypeMessage.class));
+ assertArrayEquals(toByteBuffer(FULL_TYPE_DATA).array(),
+ msg.writeToBytes(ByteOrder.BIG_ENDIAN));
+
+ final FullTypeMessage msg1 = new FullTypeMessage((short) 0xff, (int) 0xffff,
+ (long) 0xffffffffL, (long) 0x7fffffffffffffffL,
+ new BigInteger("18446744073709551615"), (byte) 0x7f, (short) 0x7fff,
+ (int) 0x7fffffff, (long) 0x7fffffffffffffffL, (int) 0x7fff, (long) 0x7fffffffL,
+ (long) 0x7fffffffffffffffL, new BigInteger("18446744073709551615"), TEST_PREFIX64,
+ MacAddress.fromString("00:11:22:33:44:55"));
+ assertTrue(msg.equals(msg1));
+ }
+
+ static class FullTypeMessageWithDupType extends Struct {
+ @Field(order = 0, type = Type.U8) public final short u8;
+ @Field(order = 1, type = Type.U16) public final int u16;
+ @Field(order = 2, type = Type.U32) public final long u32;
+ @Field(order = 3, type = Type.S64) public final long u63; // old: U63, new: S64
+ @Field(order = 4, type = Type.UBE64) public final BigInteger u64; // old: U64, new: UBE64
+ @Field(order = 5, type = Type.S8) public final byte s8;
+ @Field(order = 6, type = Type.S16) public final short s16;
+ @Field(order = 7, type = Type.S32) public final int s32;
+ @Field(order = 8, type = Type.S64) public final long s64;
+ @Field(order = 9, type = Type.U16) public final int ube16; // old:UBE16, new: U16
+ @Field(order = 10, type = Type.UBE32) public final long ube32;
+ @Field(order = 11, type = Type.UBE63) public final long ube63;
+ @Field(order = 12, type = Type.UBE64) public final BigInteger ube64;
+ @Field(order = 13, type = Type.ByteArray, arraysize = 12) public final byte[] bytes;
+ @Field(order = 14, type = Type.EUI48) public final MacAddress eui48;
+
+ FullTypeMessageWithDupType(final short u8, final int u16, final long u32, final long u63,
+ final BigInteger u64, final byte s8, final short s16, final int s32, final long s64,
+ final int ube16, final long ube32, final long ube63, final BigInteger ube64,
+ final byte[] bytes, final MacAddress eui48) {
+ this.u8 = u8;
+ this.u16 = u16;
+ this.u32 = u32;
+ this.u63 = u63;
+ this.u64 = u64;
+ this.s8 = s8;
+ this.s16 = s16;
+ this.s32 = s32;
+ this.s64 = s64;
+ this.ube16 = ube16;
+ this.ube32 = ube32;
+ this.ube63 = ube63;
+ this.ube64 = ube64;
+ this.bytes = bytes;
+ this.eui48 = eui48;
+ }
+ }
+
+ @Test
+ public void testStructClass_notEqualWithDifferentClass() {
+ final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class,
+ ByteOrder.BIG_ENDIAN);
+ final FullTypeMessageWithDupType msg1 = doParsingMessageTest(FULL_TYPE_DATA,
+ FullTypeMessageWithDupType.class, ByteOrder.BIG_ENDIAN);
+
+ assertFalse(msg.equals(msg1));
+ }
+
+ @Test
+ public void testStructClass_notEqualWithDifferentValue() {
+ final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class,
+ ByteOrder.BIG_ENDIAN);
+
+ // With different MAC address.
+ final FullTypeMessage msg1 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_MAC,
+ FullTypeMessage.class, ByteOrder.BIG_ENDIAN);
+ assertNotEquals(msg.eui48, msg1.eui48);
+ assertFalse(msg.equals(msg1));
+
+ // With different byte array.
+ final FullTypeMessage msg2 = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class,
+ ByteOrder.BIG_ENDIAN);
+ msg2.bytes[5] = (byte) 42; // change one byte in the array.
+ assertFalse(msg.equals(msg2));
+
+ // With different Long primitive.
+ final FullTypeMessage msg3 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_LONG,
+ FullTypeMessage.class, ByteOrder.BIG_ENDIAN);
+ assertNotEquals(msg.u63, msg3.u63);
+ assertFalse(msg.equals(msg3));
+
+ // With different Integer primitive.
+ final FullTypeMessage msg4 = doParsingMessageTest(FULL_TYPE_DATA_DIFF_INTEGER,
+ FullTypeMessage.class, ByteOrder.BIG_ENDIAN);
+ assertNotEquals(msg.ube32, msg4.ube32);
+ assertFalse(msg.equals(msg4));
+
+ }
+
+ @Test
+ public void testStructClass_toString() {
+ final String expected = "u8: 255, u16: 65535, u32: 4294967295,"
+ + " u63: 9223372036854775807, u64: 18446744073709551615, s8: 127, s16: 32767,"
+ + " s32: 2147483647, s64: 9223372036854775807, ube16: 32767, ube32: 2147483647,"
+ + " ube63: 9223372036854775807, ube64: 18446744073709551615,"
+ + " bytes: 0x20010DB80003000400050006,"
+ + " eui48: 00:11:22:33:44:55";
+
+ final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class,
+ ByteOrder.BIG_ENDIAN);
+ assertEquals(expected, msg.toString());
+ }
+
+ @Test
+ public void testStructClass_toStringWithNullMember() {
+ final String expected = "u8: 255, u16: 65535, u32: 4294967295,"
+ + " u63: 9223372036854775807, u64: null, s8: 127, s16: 32767,"
+ + " s32: 2147483647, s64: 9223372036854775807, ube16: 32767, ube32: 2147483647,"
+ + " ube63: 9223372036854775807, ube64: 18446744073709551615,"
+ + " bytes: null, eui48: null";
+
+ final FullTypeMessage msg = new FullTypeMessage((short) 0xff, (int) 0xffff,
+ (long) 0xffffffffL, (long) 0x7fffffffffffffffL,
+ null /* u64 */, (byte) 0x7f, (short) 0x7fff,
+ (int) 0x7fffffff, (long) 0x7fffffffffffffffL, (int) 0x7fff, (long) 0x7fffffffL,
+ (long) 0x7fffffffffffffffL, new BigInteger("18446744073709551615"),
+ null /* bytes */, null /* eui48 */);
+ assertEquals(expected, msg.toString());
+ }
+
+ @Test
+ public void testStructClass_hashcode() {
+ final FullTypeMessage msg = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class,
+ ByteOrder.BIG_ENDIAN);
+ final FullTypeMessage msg1 = doParsingMessageTest(FULL_TYPE_DATA, FullTypeMessage.class,
+ ByteOrder.BIG_ENDIAN);
+
+ assertNotEquals(0, msg.hashCode());
+ assertNotEquals(0, msg1.hashCode());
+ assertTrue(msg.equals(msg1));
+ assertEquals(msg.hashCode(), msg1.hashCode());
}
}