forked from Qortal-Forker/qortal
		
	Minor work on ByteArray and associated tests
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
			
		||||
package org.qortal.utils;
 | 
			
		||||
 | 
			
		||||
import java.math.BigInteger;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
public class ByteArray implements Comparable<ByteArray> {
 | 
			
		||||
 | 
			
		||||
@@ -8,7 +9,11 @@ public class ByteArray implements Comparable<ByteArray> {
 | 
			
		||||
	public final 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
 | 
			
		||||
@@ -16,36 +21,39 @@ public class ByteArray implements Comparable<ByteArray> {
 | 
			
		||||
		if (this == other)
 | 
			
		||||
			return true;
 | 
			
		||||
 | 
			
		||||
		if (other instanceof ByteArray)
 | 
			
		||||
			return this.compareTo((ByteArray) other) == 0;
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public int hashCode() {
 | 
			
		||||
		int h = hash;
 | 
			
		||||
		if (h == 0 && value.length > 0) {
 | 
			
		||||
			byte[] val = value;
 | 
			
		||||
		int h = this.hash;
 | 
			
		||||
		byte[] val = this.value;
 | 
			
		||||
 | 
			
		||||
		if (h == 0 && val.length > 0) {
 | 
			
		||||
			h = 1;
 | 
			
		||||
 | 
			
		||||
			for (int i = 0; i < val.length; ++i)
 | 
			
		||||
				h = 31 * h + val[i];
 | 
			
		||||
 | 
			
		||||
			hash = h;
 | 
			
		||||
			this.hash = h;
 | 
			
		||||
		}
 | 
			
		||||
		return h;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public int compareTo(ByteArray other) {
 | 
			
		||||
		return this.compareTo(other.value);
 | 
			
		||||
		Objects.requireNonNull(other);
 | 
			
		||||
		return this.compareToPrimitive(other.value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public int compareTo(byte[] otherValue) {
 | 
			
		||||
		byte[] val = value;
 | 
			
		||||
	public int compareToPrimitive(byte[] otherValue) {
 | 
			
		||||
		byte[] val = this.value;
 | 
			
		||||
 | 
			
		||||
		if (val.length < otherValue.length)
 | 
			
		||||
			return -1;
 | 
			
		||||
@@ -66,6 +74,16 @@ public class ByteArray implements Comparable<ByteArray> {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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 java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
import java.util.TreeMap;
 | 
			
		||||
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
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)
 | 
			
		||||
			map.put(new ByteArray(testValue), String.valueOf(map.size()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private byte[] dup(byte[] value) {
 | 
			
		||||
		byte[] copiedValue = new byte[value.length];
 | 
			
		||||
		System.arraycopy(value, 0, copiedValue, 0, copiedValue.length);
 | 
			
		||||
		return copiedValue;
 | 
			
		||||
	private static byte[] dup(byte[] value) {
 | 
			
		||||
		return Arrays.copyOf(value, value.length);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
@@ -92,7 +92,7 @@ public class ByteArrayTests {
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	@SuppressWarnings("unlikely-arg-type")
 | 
			
		||||
	public void testMapContainsKey() {
 | 
			
		||||
	public void testHashMapContainsKey() {
 | 
			
		||||
		Map<ByteArray, String> testMap = new HashMap<>();
 | 
			
		||||
		fillMap(testMap);
 | 
			
		||||
 | 
			
		||||
@@ -105,8 +105,59 @@ public class ByteArrayTests {
 | 
			
		||||
 | 
			
		||||
		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
 | 
			
		||||
@@ -116,8 +167,9 @@ public class ByteArrayTests {
 | 
			
		||||
 | 
			
		||||
		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("Primitive hashCode: 0x%08x", copiedValue.hashCode()));
 | 
			
		||||
		System.out.println(String.format("Duplicated primitive hashCode: 0x%08x", copiedValue.hashCode()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user