More unit tests for jdk17

This commit is contained in:
2023-09-18 18:32:52 -05:00
parent 587f8bbaf6
commit 3cd7639da1
3 changed files with 212 additions and 122 deletions

View File

@ -13,7 +13,7 @@ import java.lang.annotation.Target;
* @author Isaac Parenteau * @author Isaac Parenteau
* *
*/ */
@Target({ElementType.FIELD, ElementType.TYPE}) @Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface MapValue { public @interface MapValue {

View File

@ -4,17 +4,7 @@ import java.lang.reflect.Array;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -24,8 +14,6 @@ import java.util.stream.IntStream;
import net.locusworks.common.annotations.MapValue; import net.locusworks.common.annotations.MapValue;
import net.locusworks.common.interfaces.ThrowingConsumer; import net.locusworks.common.interfaces.ThrowingConsumer;
import java.util.Set;
/*** /***
* Utils class with generic methods * Utils class with generic methods
* @author Isaac Parenteau * @author Isaac Parenteau
@ -110,49 +98,33 @@ public class Utils {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <K, V> Map<K, V> buildMap(Class<?> mapClass, Class<K> mapKey, Class<V> mapValue, Object... data) { public static <K, V> Map<K, V> buildMap(Class<?> mapClass, Class<K> mapKey, Class<V> mapValue, Object... data) {
Objects.requireNonNull(mapKey, "Null key value");
Objects.requireNonNull(mapValue, "Null map value");
Map<K, V> results; Map<K, V> results;
try { try {
results = (Map<K, V>) mapClass.getDeclaredConstructor().newInstance(); results = (Map<K, V>) mapClass.getDeclaredConstructor().newInstance();
} catch (Exception ex) { } catch (Exception ex) {
throw new IllegalArgumentException("Unable to create instance of " + mapClass.getSimpleName()); throw new IllegalArgumentException("Unable to create instance of " + mapClass.getSimpleName() + " e: " + ex.getMessage());
} }
if (data.length % 2 != 0) { if (data.length % 2 != 0) {
throw new IllegalArgumentException("Odd number of arguments provided"); throw new IllegalArgumentException("Odd number of arguments provided");
} }
Object key = null; for(int i = 0; i < data.length; i+=2) {
int step = -1; Object key = data[i];
Object value = data[i + 1];
for (Object value : data) { if (!mapKey.isInstance(key)) {
switch(++step % 2) { throw new IllegalArgumentException("Key is not the correct instance. Expecting " + mapKey.getName() + " Received " + key.getClass().getName());
case 0:
if (mapKey == null) {
throw new IllegalArgumentException("Null key value");
}
if (value instanceof Class) {
try {
value = ((Class<?>)value).getDeclaredConstructor().newInstance();
} catch (Exception ex) {
throw new IllegalArgumentException("Unable to create new instance of " + value);
}
}
if (!mapKey.isInstance(value)) {
throw new IllegalArgumentException("Key is not the correct instance. Expecting " + mapKey.getName() + " Received " + value.getClass().getName());
}
key = value;
continue;
case 1:
if (!mapValue.isInstance(value)) {
throw new IllegalArgumentException("Value is not the correct instance. Expecting " + mapValue.getName() + " Received " + value.getClass().getName());
}
results.put((K) key, (V) value);
break;
default:
throw new IllegalAccessError("Calculation for step was not a multiple of two. This shouldn't have happened");
} }
if (!mapValue.isInstance(value)) {
throw new IllegalArgumentException("Value is not the correct instance. Expecting " + mapValue.getName() + " Received " + value.getClass().getName());
}
results.put((K) key, (V) value);
} }
return results; return results;
} }
@ -161,28 +133,24 @@ public class Utils {
* Builds a set of objects * Builds a set of objects
* @param setClass Class type of the set to create * @param setClass Class type of the set to create
* @param setValue Class type of the objects being placed in the set * @param setValue Class type of the objects being placed in the set
* @param <V> Class type of the return object (should be the same as setValue) * @param <E> Class type of the return object (should be the same as setValue)
* @param data Data to place inside the set * @param data Data to place inside the set
* @return Set filled with the data * @return Set filled with the data
* @deprecated since JDk11 can use Set.of
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <V> Set<V> buildSet(Class<?> setClass, Class<V> setValue, Object... data) { public static <E> Set<E> buildSet(Class<?> setClass, Class<E> setValue, E... data) {
Set<V> results; return buildSet(data);
}
try { /**
results = (Set<V>) setClass.getDeclaredConstructor().newInstance(); * Builds a set of objects
} catch (Exception ex) { * @param data the data to set
throw new IllegalArgumentException("Unable to create instance of " + setClass.getSimpleName()); * @return the set
} * @param <E> the type
*/
for (Object value : data) { @SafeVarargs public static <E> Set<E> buildSet(E... data) {
if (!setValue.isInstance(value)) { return Set.of(data);
throw new IllegalArgumentException("Value is not the correct instance. Expecting " + setValue.getName() + " Received " + value.getClass().getName());
}
results.add((V) value);
}
return results;
} }
/** /**
@ -197,23 +165,12 @@ public class Utils {
} }
/** /**
* Clone list. * Clone list and makes it unmodifiable.
* *
* @param <E> the type parameter * @return unmodifiable list
* @param list the list
*
* @return the list
* @throws IllegalAccessException throw when an object in the list cannot be accessed through reflection
* @throws InstantiationException thrown when an object in the list cannot be instantiated through reflection
*/ */
@SuppressWarnings("unchecked") public static <E> List<E> cloneList(List<E> list) {
public static <E> List<E> cloneList(List<E> list) return Collections.unmodifiableList(list);
throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
List<E> clone = new ArrayList<>();
for (E item : list) {
clone.add((E) cloneObject(item));
}
return clone;
} }
/** /**
@ -223,7 +180,8 @@ public class Utils {
* @throws IllegalAccessException thrown when the filed cannot be access * @throws IllegalAccessException thrown when the filed cannot be access
* @throws InstantiationException Thrown when the object cannot be instantiated * @throws InstantiationException Thrown when the object cannot be instantiated
*/ */
public static Object cloneObject(Object obj) @SuppressWarnings("unchecked")
public static <O> O cloneObject(O obj)
throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Object clone = obj.getClass().getDeclaredConstructor().newInstance(); Object clone = obj.getClass().getDeclaredConstructor().newInstance();
for (Field field : obj.getClass().getDeclaredFields()) { for (Field field : obj.getClass().getDeclaredFields()) {
@ -232,9 +190,10 @@ public class Utils {
if (field.get(obj) == null || Modifier.isFinal(field.getModifiers())){ if (field.get(obj) == null || Modifier.isFinal(field.getModifiers())){
continue; continue;
} }
if (field.getType().isPrimitive() || field.getType().equals(String.class)
|| field.getType().getSuperclass().equals(Number.class) Class<?> type = field.getType();
|| field.getType().equals(Boolean.class)){
if (type.isPrimitive() || getWrapperTypes().contains(type)) {
field.set(clone, field.get(obj)); field.set(clone, field.get(obj));
} else { } else {
Object childObj = field.get(obj); Object childObj = field.get(obj);
@ -246,7 +205,7 @@ public class Utils {
} }
} catch (NullPointerException ignored) { } } catch (NullPointerException ignored) { }
} }
return clone; return (O) clone;
} }
/*** /***
@ -260,18 +219,17 @@ public class Utils {
Class<?> clazz = obj.getClass(); Class<?> clazz = obj.getClass();
Map<String, Object> map = new LinkedHashMap<>(); Map<String, Object> map = new LinkedHashMap<>();
boolean hasAnnotations = clazz.isAnnotationPresent(MapValue.class);
for (Field field : clazz.getDeclaredFields()) { for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true); field.setAccessible(true);
boolean hasAnnotations = field.isAnnotationPresent(MapValue.class);
String key = field.getName(); String key = field.getName();
Object value = field.get(obj); Object value = field.get(obj);
if (value == null) continue; if (value == null) continue;
if (hasAnnotations) { if (hasAnnotations) {
if (!field.isAnnotationPresent(MapValue.class)) {
continue;
}
MapValue annotation = field.getDeclaredAnnotation(MapValue.class); MapValue annotation = field.getDeclaredAnnotation(MapValue.class);
if (annotation.ignore()) { if (annotation.ignore()) {
continue; continue;
@ -303,6 +261,12 @@ public class Utils {
return convert; return convert;
} }
/**
* Converts an object toa string map;
* @param obj the object to convert
* @return the map
* @throws Exception thrown if something happens
*/
public static Map<String, String> convertToStringMap(Object obj) throws Exception { public static Map<String, String> convertToStringMap(Object obj) throws Exception {
return convertToStringMap(convertToMap(obj)); return convertToStringMap(convertToMap(obj));
} }
@ -459,6 +423,27 @@ public class Utils {
return tmpList; return tmpList;
} }
/**
* Use reflection to get the field values
* @param clazz the class to find the field
* @param fieldName the field name
* @return field
*/
private static Field getField(Class<?> clazz, String fieldName) {
Field field = null;
while(clazz != null) {
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
break;
} catch(Exception ex) {
clazz = clazz.getSuperclass();
}
}
return field;
}
/** /**
* A replacement for String.format. Allows for to many parameters or too few * A replacement for String.format. Allows for to many parameters or too few
* Replaces {} in the string in order. * Replaces {} in the string in order.
@ -503,27 +488,6 @@ public class Utils {
return obj == null ? "Unknown" : (verbose ? obj.getClass().getName() : obj.getClass().getSimpleName()); return obj == null ? "Unknown" : (verbose ? obj.getClass().getName() : obj.getClass().getSimpleName());
} }
/**
* Use reflection to get the field values
* @param clazz the class to find the field
* @param fieldName the field name
* @return field
*/
private static Field getField(Class<?> clazz, String fieldName) {
Field field = null;
while(clazz != null) {
try {
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
break;
} catch(Exception ex) {
clazz = clazz.getSuperclass();
}
}
return field;
}
/** /**
* Get a value from a map * Get a value from a map
* *
@ -1076,16 +1040,16 @@ public class Utils {
} }
private static Set<Class<?>> getWrapperTypes() { private static Set<Class<?>> getWrapperTypes() {
Set<Class<?>> ret = new HashSet<>(); return Set.of(
ret.add(Boolean.class); Boolean.class,
ret.add(Character.class); Character.class,
ret.add(Byte.class); Byte.class,
ret.add(Short.class); Short.class,
ret.add(Integer.class); Integer.class,
ret.add(Long.class); Long.class,
ret.add(Float.class); Float.class,
ret.add(Double.class); Double.class,
ret.add(String.class); String.class
return ret; );
} }
} }

View File

@ -1,15 +1,14 @@
package net.locusworks.test; package net.locusworks.test;
import net.locusworks.common.annotations.MapValue;
import net.locusworks.common.utils.Utils; import net.locusworks.common.utils.Utils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import java.util.Collections; import java.lang.reflect.InvocationTargetException;
import java.util.List; import java.util.*;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Stream; import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -110,9 +109,136 @@ public class UtilsTest {
assertEquals("World", mymap.get("Hello")); assertEquals("World", mymap.get("Hello"));
} }
@Test
public void testCloneList() {
String[] values = new String[]{
"Hello",
"world"
};
List<String> cloned = Utils.cloneList(new ArrayList<>(Arrays.stream(values).toList()));
assertEquals(2, cloned.size());
assertThrows(UnsupportedOperationException.class, () -> cloned.add("asdf"));
}
@Test
public void testCloneObject()
throws InvocationTargetException, InstantiationException, IllegalAccessException,
NoSuchMethodException {
TestClass clazz = new TestClass();
clazz.field1 = "hi";
clazz.field2 = "low";
clazz.field3 = "world";
TestClass clazz3 = new TestClass();
clazz3.field1 = "hi";
clazz3.field2 = "smash";
clazz3.field3 = "world";
clazz.testClass = clazz3;
TestClass clazz2 = Utils.cloneObject(clazz);
assertNotNull(clazz2);
assertEquals(clazz.field1, clazz2.field1);
assertEquals(clazz.field2, clazz2.field2);
assertEquals(clazz.field3, clazz2.field3);
assertEquals(clazz.field5, clazz2.field5);
assertEquals(clazz.number, clazz2.number);
assertEquals(clazz.aBoolean, clazz2.aBoolean);
assertNotNull(clazz2.field4);
assertNull(clazz2.nullField);
}
@Test
public void testCovertToMap() throws Exception {
TestClass clazz = new TestClass();
clazz.field1 = "hi";
clazz.field2 = "low";
clazz.field3 = "world";
TestClass clazz3 = new TestClass();
clazz.field1 = "hi";
clazz.field2 = "low";
clazz.field3 = "world";
clazz.testClass = clazz3;
Map<String, Object> converted = Utils.convertToMap(clazz);
assertEquals(7, converted.size());
assertEquals("hi", converted.get("other_field"));
}
@Test
public void testConvertToStringMap() throws Exception {
TestClass clazz = new TestClass();
clazz.field1 = "hi";
clazz.field2 = "low";
clazz.field3 = "world";
Map<String, String> converted = Utils.convertToStringMap(clazz);
assertEquals(6, converted.size());
assertEquals("hi", converted.get("other_field"));
converted = Utils.convertToStringMap(converted);
assertEquals(6, converted.size());
assertEquals("hi", converted.get("other_field"));
}
@Test
public void testBuildStringMap() {
Map<String, String> myMap = Utils.buildStringHashMap("hello", "world");
assertNotNull(myMap);
assertEquals(1, myMap.size());
}
@Test
public void testBuildMapExceptions() {
Throwable ex = assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(String.class, String.class, String.class, "" ));
assertNotNull(ex);
ex = assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, String.class, String.class, "Hello"));
assertEquals("Odd number of arguments provided", ex.getMessage());
assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, String.class, String.class, new Object(), "Hello"));
assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, String.class, String.class, "Hello", new Object()));
assertThrows(IllegalArgumentException.class, () -> Utils.buildMap(TreeMap.class, Object.class, String.class, "Hello", new Object()));
}
@Test
public void testBuildSet() {
Set<String> myset = Utils.buildSet("Hello", "World");
assertNotNull(myset);
assertEquals(2, myset.size());
}
@Test @Test
public void testIsJunitRunning() { public void testIsJunitRunning() {
assertTrue(Utils.isJUnitRunning()); assertTrue(Utils.isJUnitRunning());
} }
public static class TestClass {
@MapValue("other_field")
private String field1;
@MapValue(ignore = true)
private String field2;
private String field3;
private final String field4 = "final";
@MapValue
private int field5 = 5;
private Boolean aBoolean = Boolean.valueOf("true");
private Double number = 1.0d;
private String nullField = null;
private TestClass testClass;
}
} }