forked from Qortal/qortal
Minor work on ByteArray and associated tests
This commit is contained in:
parent
8c9cf4a02d
commit
e8fc91fd34
@ -1,6 +1,7 @@
|
|||||||
package org.qortal.utils;
|
package org.qortal.utils;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class ByteArray implements Comparable<ByteArray> {
|
public class ByteArray implements Comparable<ByteArray> {
|
||||||
|
|
||||||
@ -8,7 +9,11 @@ public class ByteArray implements Comparable<ByteArray> {
|
|||||||
public final byte[] value;
|
public final byte[] value;
|
||||||
|
|
||||||
public ByteArray(byte[] value) {
|
public ByteArray(byte[] value) {
|
||||||
this.value = value;
|
this.value = Objects.requireNonNull(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteArray of(byte[] value) {
|
||||||
|
return new ByteArray(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -16,36 +21,39 @@ public class ByteArray implements Comparable<ByteArray> {
|
|||||||
if (this == other)
|
if (this == other)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (other instanceof ByteArray)
|
|
||||||
return this.compareTo((ByteArray) other) == 0;
|
|
||||||
|
|
||||||
if (other instanceof byte[])
|
if (other instanceof byte[])
|
||||||
return this.compareTo((byte[]) other) == 0;
|
return Arrays.equals(this.value, (byte[]) other);
|
||||||
|
|
||||||
|
if (other instanceof ByteArray)
|
||||||
|
return Arrays.equals(this.value, ((ByteArray) other).value);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int h = hash;
|
int h = this.hash;
|
||||||
if (h == 0 && value.length > 0) {
|
byte[] val = this.value;
|
||||||
byte[] val = value;
|
|
||||||
|
if (h == 0 && val.length > 0) {
|
||||||
|
h = 1;
|
||||||
|
|
||||||
for (int i = 0; i < val.length; ++i)
|
for (int i = 0; i < val.length; ++i)
|
||||||
h = 31 * h + val[i];
|
h = 31 * h + val[i];
|
||||||
|
|
||||||
hash = h;
|
this.hash = h;
|
||||||
}
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ByteArray other) {
|
public int compareTo(ByteArray other) {
|
||||||
return this.compareTo(other.value);
|
Objects.requireNonNull(other);
|
||||||
|
return this.compareToPrimitive(other.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int compareTo(byte[] otherValue) {
|
public int compareToPrimitive(byte[] otherValue) {
|
||||||
byte[] val = value;
|
byte[] val = this.value;
|
||||||
|
|
||||||
if (val.length < otherValue.length)
|
if (val.length < otherValue.length)
|
||||||
return -1;
|
return -1;
|
||||||
@ -66,6 +74,16 @@ public class ByteArray implements Comparable<ByteArray> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("%x", new BigInteger(1, this.value));
|
StringBuilder sb = new StringBuilder(3 + this.value.length * 6);
|
||||||
|
sb.append("[");
|
||||||
|
|
||||||
|
if (this.value.length > 0)
|
||||||
|
sb.append(this.value[0]);
|
||||||
|
|
||||||
|
for (int i = 1; i < this.value.length; ++i)
|
||||||
|
sb.append(", ").append(this.value[i]);
|
||||||
|
|
||||||
|
return sb.append("]").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,12 @@ package org.qortal.test;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -28,15 +30,13 @@ public class ByteArrayTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillMap(Map<ByteArray, String> map) {
|
private static void fillMap(Map<ByteArray, String> map) {
|
||||||
for (byte[] testValue : testValues)
|
for (byte[] testValue : testValues)
|
||||||
map.put(new ByteArray(testValue), String.valueOf(map.size()));
|
map.put(new ByteArray(testValue), String.valueOf(map.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] dup(byte[] value) {
|
private static byte[] dup(byte[] value) {
|
||||||
byte[] copiedValue = new byte[value.length];
|
return Arrays.copyOf(value, value.length);
|
||||||
System.arraycopy(value, 0, copiedValue, 0, copiedValue.length);
|
|
||||||
return copiedValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -92,7 +92,7 @@ public class ByteArrayTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unlikely-arg-type")
|
@SuppressWarnings("unlikely-arg-type")
|
||||||
public void testMapContainsKey() {
|
public void testHashMapContainsKey() {
|
||||||
Map<ByteArray, String> testMap = new HashMap<>();
|
Map<ByteArray, String> testMap = new HashMap<>();
|
||||||
fillMap(testMap);
|
fillMap(testMap);
|
||||||
|
|
||||||
@ -105,8 +105,59 @@ public class ByteArrayTests {
|
|||||||
|
|
||||||
assertTrue("boxed not equal to primitive", ba.equals(copiedValue));
|
assertTrue("boxed not equal to primitive", ba.equals(copiedValue));
|
||||||
|
|
||||||
// This won't work because copiedValue.hashCode() will not match ba.hashCode()
|
/*
|
||||||
assertFalse("Primitive shouldn't be found in map", testMap.containsKey(copiedValue));
|
* Unfortunately this doesn't work because HashMap::containsKey compares hashCodes first,
|
||||||
|
* followed by object references, and copiedValue.hashCode() will never match ba.hashCode().
|
||||||
|
*/
|
||||||
|
assertFalse("Primitive shouldn't be found in HashMap", testMap.containsKey(copiedValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unlikely-arg-type")
|
||||||
|
public void testTreeMapContainsKey() {
|
||||||
|
Map<ByteArray, String> testMap = new TreeMap<>();
|
||||||
|
fillMap(testMap);
|
||||||
|
|
||||||
|
// Create new ByteArray object with an existing value.
|
||||||
|
byte[] copiedValue = dup(testValues.get(3));
|
||||||
|
ByteArray ba = new ByteArray(copiedValue);
|
||||||
|
|
||||||
|
// Confirm object can be found in map
|
||||||
|
assertTrue("ByteArray not found in map", testMap.containsKey(ba));
|
||||||
|
|
||||||
|
assertTrue("boxed not equal to primitive", ba.equals(copiedValue));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unfortunately this doesn't work because TreeMap::containsKey(x) wants to cast x to
|
||||||
|
* Comparable<? super ByteArray> and byte[] does not fit <? super ByteArray>
|
||||||
|
* so this throws a ClassCastException.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
assertFalse("Primitive shouldn't be found in TreeMap", testMap.containsKey(copiedValue));
|
||||||
|
fail();
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unlikely-arg-type")
|
||||||
|
public void testArrayListContains() {
|
||||||
|
// Create new ByteArray object with an existing value.
|
||||||
|
byte[] copiedValue = dup(testValues.get(3));
|
||||||
|
ByteArray ba = new ByteArray(copiedValue);
|
||||||
|
|
||||||
|
// Confirm object can be found in list
|
||||||
|
assertTrue("ByteArray not found in map", testValues.contains(ba));
|
||||||
|
|
||||||
|
assertTrue("boxed not equal to primitive", ba.equals(copiedValue));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unfortunately this doesn't work because ArrayList::contains performs
|
||||||
|
* copiedValue.equals(x) for each x in testValues, and byte[].equals()
|
||||||
|
* simply compares object references, so will never match any ByteArray.
|
||||||
|
*/
|
||||||
|
assertFalse("Primitive shouldn't be found in ArrayList", testValues.contains(copiedValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -116,8 +167,9 @@ public class ByteArrayTests {
|
|||||||
|
|
||||||
byte[] copiedValue = dup(testValue);
|
byte[] copiedValue = dup(testValue);
|
||||||
|
|
||||||
|
System.out.println(String.format("Primitive hashCode: 0x%08x", testValue.hashCode()));
|
||||||
System.out.println(String.format("Boxed hashCode: 0x%08x", ba1.hashCode()));
|
System.out.println(String.format("Boxed hashCode: 0x%08x", ba1.hashCode()));
|
||||||
System.out.println(String.format("Primitive hashCode: 0x%08x", copiedValue.hashCode()));
|
System.out.println(String.format("Duplicated primitive hashCode: 0x%08x", copiedValue.hashCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user