new name, new functionality
This commit is contained in:
parent
8a8dc9d9de
commit
4d4ebe9c7f
36 changed files with 904 additions and 533 deletions
11
README.md
11
README.md
|
|
@ -1,8 +1,15 @@
|
|||
# Apples
|
||||
# reflective
|
||||
Utility classes that use ASM for generating metaclasses as if it were standard java reflection, but without the performance overhead.
|
||||
|
||||
|
||||
__nl.sander.reflective.compare.Compare__
|
||||
* universal (deep) compare tool
|
||||
* compares [apple] to [orange] recursively and shows the diff
|
||||
* no reflection
|
||||
* compiles to bytecode version jdk11
|
||||
* but also handles records, if you run jdk16+
|
||||
* Can optionally do 'structural comparison' (as opposed to _nominal_ like in the respective types of polymorphism). Let's say you have class Apple with property _color_ and a class Orange, also with property _color_. `Compare` provides `any` method with which you can compare the values disregarding the type that contains them.
|
||||
|
||||
__nl.sander.reflective.tomap.ToMap__
|
||||
* turn any bean/record in a Map<String, Object>
|
||||
|
||||
* I have one more wish for this and that is 'structural comparison'. Let's say you have class Apple with property _color_ and a class Orange, also with property _color_. Right now `Apples` does the sensible thing, and that is saying: "classes don't match". But what what if you could compare these apples and oranges? Should be possible.
|
||||
6
pom.xml
6
pom.xml
|
|
@ -3,10 +3,10 @@
|
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>nl.sander</groupId>
|
||||
<artifactId>Apples</artifactId>
|
||||
<artifactId>reflective</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>Comparator</name>
|
||||
<description>Comparator</description>
|
||||
<name>reflective</name>
|
||||
<description>Reflective utils that don't use java.lang.reflect</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
package nl.sander.apples;
|
||||
|
||||
public abstract class BaseApple {
|
||||
|
||||
public abstract Result compare(Object apple, Object orange);
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package nl.sander.reflective.compare;
|
||||
|
||||
public abstract class AbstractComparator {
|
||||
|
||||
public abstract Result compare(Object apple, Object orange);
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import nl.sander.reflective.java.Java;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
|
@ -9,16 +10,14 @@ import java.util.UUID;
|
|||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
class AppleFactory extends ClassVisitor {
|
||||
class ComparatorFactory extends ClassVisitor {
|
||||
|
||||
public static final String SUPER = javaName(BaseApple.class.getName());
|
||||
public static final String SUPER = Java.internalName(AbstractComparator.class);
|
||||
|
||||
public static final String INIT = "<init>";
|
||||
public static final String ZERO_ARGS_VOID = "()V";
|
||||
|
||||
private boolean isRecord = false;
|
||||
|
||||
public AppleFactory() {
|
||||
public ComparatorFactory() {
|
||||
super(ASM9);
|
||||
}
|
||||
|
||||
|
|
@ -40,52 +39,41 @@ class AppleFactory extends ClassVisitor {
|
|||
classNode.superName = SUPER;
|
||||
classNode.version = V11;
|
||||
classNode.access = ACC_PUBLIC;
|
||||
MethodNode constructor = new MethodNode(ACC_PUBLIC, INIT, ZERO_ARGS_VOID, null, null);
|
||||
MethodNode constructor = new MethodNode(ACC_PUBLIC, Java.INIT, Java.ZERO_ARGS_VOID, null, null);
|
||||
constructor.instructions.add(new VarInsnNode(ALOAD, 0));
|
||||
constructor.instructions.add(new MethodInsnNode(INVOKESPECIAL, SUPER, INIT, ZERO_ARGS_VOID));
|
||||
constructor.instructions.add(new MethodInsnNode(INVOKESPECIAL, SUPER, Java.INIT, Java.ZERO_ARGS_VOID));
|
||||
constructor.instructions.add(new InsnNode(RETURN));
|
||||
classNode.methods.add(constructor);
|
||||
|
||||
compareMethod = new MethodNode(ACC_PUBLIC,
|
||||
"compare", "(Ljava/lang/Object;Ljava/lang/Object;)Lnl/sander/apples/Result;", null, null);
|
||||
"compare", "(Ljava/lang/Object;Ljava/lang/Object;)L" + Java.internalName(Result.class) + ";", null, null);
|
||||
classNode.methods.add(compareMethod);
|
||||
add(new VarInsnNode(ALOAD, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String methodname,
|
||||
String desc, String signature, String[] exceptions) {
|
||||
if (!hasArgs(desc) && access == Modifier.PUBLIC && isRecord ||
|
||||
if (!Java.hasArgs(desc) && access == Modifier.PUBLIC && isRecord ||
|
||||
(methodname.startsWith("get") || (methodname.startsWith("is")) && desc.equals("()Z"))) {
|
||||
visitGetter(methodname, asProperty(methodname, isRecord), getReturnType(desc));
|
||||
visitGetter(methodname, Java.asProperty(methodname, isRecord), Java.getReturnType(desc));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String asProperty(String getter, boolean isRecord) {
|
||||
if (isRecord){
|
||||
return getter;
|
||||
} else {
|
||||
if (getter.startsWith("get")){
|
||||
return getter.substring(3,4).toLowerCase()+getter.substring(4);
|
||||
} else {
|
||||
return getter.substring(2,3).toLowerCase()+getter.substring(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visitGetter(String getterMethodName, String propertyName, String returnType) {
|
||||
add(new LdcInsnNode(propertyName));
|
||||
add(new VarInsnNode(ALOAD, 1));
|
||||
add(new TypeInsnNode(CHECKCAST, javaName(classToMap)));
|
||||
add(new TypeInsnNode(CHECKCAST, Java.internalName(classToMap)));
|
||||
add(new MethodInsnNode(INVOKEVIRTUAL, classToMap, getterMethodName, "()" + returnType));
|
||||
|
||||
add(new VarInsnNode(ALOAD, 2));
|
||||
add(new TypeInsnNode(CHECKCAST, javaName(classToMap)));
|
||||
add(new TypeInsnNode(CHECKCAST, Java.internalName(classToMap)));
|
||||
add(new MethodInsnNode(INVOKEVIRTUAL, classToMap, getterMethodName, "()" + returnType));
|
||||
|
||||
add(new MethodInsnNode(INVOKESTATIC, "nl/sander/apples/Apples", "compare", "("
|
||||
add(new MethodInsnNode(INVOKESTATIC, Java.internalName(Compare.class), "compare", "("
|
||||
+ getSignature(returnType)
|
||||
+ ")Lnl/sander/apples/Result;"));
|
||||
+ ")L" + Java.internalName(Result.class) + ";"));
|
||||
add(new VarInsnNode(ASTORE, 3 + (localVarIndex++)));
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +94,7 @@ class AppleFactory extends ClassVisitor {
|
|||
} else {
|
||||
add(new LdcInsnNode(localVarIndex));
|
||||
}
|
||||
add(new TypeInsnNode(ANEWARRAY, "nl/sander/apples/Result"));
|
||||
add(new TypeInsnNode(ANEWARRAY, Java.internalName(Result.class)));
|
||||
|
||||
for (int i = 0; i < localVarIndex; i++) {
|
||||
add(new InsnNode(DUP));
|
||||
|
|
@ -119,7 +107,7 @@ class AppleFactory extends ClassVisitor {
|
|||
add(new InsnNode(AASTORE));
|
||||
}
|
||||
|
||||
add(new MethodInsnNode(INVOKESTATIC, "nl/sander/apples/Result", "merge", "([Lnl/sander/apples/Result;)Lnl/sander/apples/Result;"));
|
||||
add(new MethodInsnNode(INVOKESTATIC, Java.internalName(Result.class), "merge", "([L" + Java.internalName(Result.class) + ";)L" + Java.internalName(Result.class) + ";"));
|
||||
add(new InsnNode(ARETURN));
|
||||
}
|
||||
|
||||
|
|
@ -127,16 +115,5 @@ class AppleFactory extends ClassVisitor {
|
|||
compareMethod.instructions.add(ins);
|
||||
}
|
||||
|
||||
private String getReturnType(String desc) {
|
||||
return desc.substring(2);
|
||||
}
|
||||
|
||||
private boolean hasArgs(String desc) {
|
||||
return desc.charAt(1) != ')';
|
||||
}
|
||||
|
||||
private static String javaName(String className) {
|
||||
return className.replaceAll("\\.", "/");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,24 +1,73 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import nl.sander.reflective.java.ByteClassLoader;
|
||||
import nl.sander.reflective.java.Java;
|
||||
import nl.sander.reflective.tomap.ToMap;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public class Apples {
|
||||
/**
|
||||
* Deep (recursive) comparison of two objects
|
||||
* - floating point comparison with optional precision
|
||||
* - objects of same type or differing types, allowing comparison of types that have the same data or subsets
|
||||
*
|
||||
* In case of maps or differing object types, every item in apple is expected in orange, so apple can be subset of orange.
|
||||
*/
|
||||
public class Compare {
|
||||
private final static Map<Character, String> CHAR_ESCAPES = Map.of('\t', "\\t", '\b', "\\b", '\n', "\\n", '\r', "\\r", '\f', "\\f", '\\', "\\\\");
|
||||
|
||||
private static final ByteClassLoader generatedClassesLoader = new ByteClassLoader();
|
||||
private final static ConcurrentMap<Class<?>, AbstractComparator> cache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Compares two objects. They are assumed to be of the same type, otherwise that is the difference
|
||||
*
|
||||
* @param apple first object for comparison
|
||||
* @param orange second object for comparison
|
||||
* @return A Result object with the outcome and some details
|
||||
*
|
||||
* throws nothing but Result can wrap an exception instead of an actual comparison (rust style exception handling)
|
||||
*/
|
||||
public static Result compare(Object apple, Object orange) {
|
||||
return compare("", apple, orange);
|
||||
return compare("", apple, orange, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two objects. They are not assumed to be of the same type.
|
||||
*
|
||||
* @param apple first object for comparison
|
||||
* @param orange second object for comparison
|
||||
* @return A Result object with the outcome and some details
|
||||
* throws nothing but Result can wrap an exception instead of an actual comparison (rust style exception handling)
|
||||
*/
|
||||
public static Result any(Object apple, Object orange) {
|
||||
return compare("", apple, orange, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of same compare method where you can specify a common property for the two objects to compare.
|
||||
* This is primarily useful for doing bean/record property comparison.
|
||||
*
|
||||
* @param property common property (key) for apple and orange
|
||||
* @param apple first object for comparison
|
||||
* @param orange second object for comparison
|
||||
* @return A Result object with the outcome and some details
|
||||
* throws nothing but Result can wrap an exception instead of an actual comparison (rust style exception handling)
|
||||
*/
|
||||
public static Result compare(String property, Object apple, Object orange) {
|
||||
return compare(property, apple, orange, false);
|
||||
}
|
||||
|
||||
|
||||
static Result compare(String property, Object apple, Object orange, boolean allowDifferingTypes) {
|
||||
try {
|
||||
if (apple == null) {
|
||||
return Result.from(property, orange == null, "null != " + asString(orange));
|
||||
}
|
||||
|
|
@ -31,9 +80,15 @@ public class Apples {
|
|||
return Result.SAME;
|
||||
}
|
||||
|
||||
|
||||
if (apple.getClass() != orange.getClass()) {
|
||||
if (allowDifferingTypes) {
|
||||
// convert objects to maps and compare their keys/values
|
||||
return compareMaps(property, ToMap.map(apple), (Map<?, ?>) ToMap.map(orange), allowDifferingTypes);
|
||||
} else {
|
||||
return Result.unequal(property, asString(apple) + " != " + asString(orange));
|
||||
}
|
||||
}
|
||||
|
||||
if (apple instanceof String) {
|
||||
return Result.from(property, apple.equals(orange), () -> asString(apple) + " != " + asString(orange));
|
||||
|
|
@ -44,11 +99,11 @@ public class Apples {
|
|||
}
|
||||
|
||||
if (apple instanceof Collection) {
|
||||
return compareCollections(property, (Collection<?>) apple, (Collection<?>) orange);
|
||||
return compareCollections(property, (Collection<?>) apple, (Collection<?>) orange, allowDifferingTypes);
|
||||
}
|
||||
|
||||
if (apple instanceof Map) {
|
||||
return compareMaps(property, (Map<?, ?>) apple, (Map<?, ?>) orange);
|
||||
return compareMaps(property, (Map<?, ?>) apple, (Map<?, ?>) orange, allowDifferingTypes);
|
||||
}
|
||||
|
||||
if (apple instanceof Comparable<?>) {
|
||||
|
|
@ -59,39 +114,54 @@ public class Apples {
|
|||
return Result.from(property, false, apple + " != " + orange);
|
||||
}
|
||||
}
|
||||
|
||||
return cache.computeIfAbsent(apple.getClass(), k -> createComparator(apple))
|
||||
.compare(apple, orange);
|
||||
} catch (Exception e) {
|
||||
return Result.error(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
private static AbstractComparator createComparator(Object apple) {
|
||||
try {
|
||||
ClassReader cr = new ClassReader(apple.getClass().getName());
|
||||
AppleFactory appleFactory = new AppleFactory();
|
||||
cr.accept(appleFactory, ClassReader.SKIP_FRAMES);
|
||||
ClassReader cr = Java.getClassReader(apple);
|
||||
|
||||
ComparatorFactory comparatorFactory = new ComparatorFactory();
|
||||
cr.accept(comparatorFactory, ClassReader.SKIP_FRAMES);
|
||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
|
||||
appleFactory.classNode.accept(classWriter);
|
||||
comparatorFactory.classNode.accept(classWriter);
|
||||
byte[] byteArray = classWriter.toByteArray();
|
||||
|
||||
generatedClassesLoader.addClass(appleFactory.classNode.name, byteArray);
|
||||
BaseApple baseApple = (BaseApple) generatedClassesLoader.loadClass(appleFactory.classNode.name).getConstructor().newInstance();
|
||||
return baseApple.compare(apple, orange);
|
||||
ByteClassLoader.INSTANCE.addClass(comparatorFactory.classNode.name, byteArray);
|
||||
return (AbstractComparator) ByteClassLoader.INSTANCE.loadClass(comparatorFactory.classNode.name).getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Result compareCollections(String property, Collection<?> apple, Collection<?> orange) {
|
||||
private static Result compareCollections(String property, Collection<?> apple, Collection<?> orange, boolean allowDifferingTypes) {
|
||||
List<String> diffs =
|
||||
zipAndEnumerate(apple, orange)
|
||||
.map(t -> new Tuple4<Integer, Object, Object, Result>(t.e1, apple, orange, Apples.compare(property, t.e2, t.e3)))
|
||||
.map(t -> {
|
||||
try {
|
||||
return new Tuple4<Integer, Object, Object, Result>(t.e1, apple, orange, Compare.compare(property, t.e2, t.e3, allowDifferingTypes));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);//meh
|
||||
}
|
||||
})
|
||||
.filter(t -> !t.e4.areEqual())
|
||||
.map(t -> property + "[" + t.e1 + "]:" + t.e2 + " != " + t.e3)
|
||||
.collect(Collectors.toList());
|
||||
return new Result(!diffs.isEmpty(), diffs);
|
||||
}
|
||||
|
||||
private static Result compareMaps(String property, Map<?, ?> apple, Map<?, ?> orange) {
|
||||
private static Result compareMaps(String property, Map<?, ?> apple, Map<?, ?> orange, boolean allowDifferingTypes) throws Exception {
|
||||
List<String> diffs = new ArrayList<>();
|
||||
for (Map.Entry<?, ?> appleEntry : apple.entrySet()) {
|
||||
Object appleValue = appleEntry.getValue();
|
||||
Object orangeValue = orange.get(appleEntry.getKey());
|
||||
Result result = Apples.compare(property + "[" + appleEntry.getKey() + "]", appleValue, orangeValue);
|
||||
Result result = Compare.compare(property + "[" + appleEntry.getKey() + "]", appleValue, orangeValue, allowDifferingTypes);
|
||||
if (!result.areEqual()) {
|
||||
diffs.addAll(result.getDiffs());
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
|
@ -6,18 +6,30 @@ import java.util.Objects;
|
|||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SuppressWarnings("unused") // used by generated code
|
||||
public class Result {
|
||||
private final boolean areEqual;
|
||||
private final List<String> diffs;
|
||||
|
||||
private final Throwable e;
|
||||
|
||||
public Result(boolean areEqual, List<String> diffs) {
|
||||
this.areEqual = areEqual;
|
||||
this.diffs = diffs;
|
||||
this.e = null;
|
||||
}
|
||||
|
||||
public static Result SAME = new Result(true, List.of());
|
||||
|
||||
public Result(Throwable e) {
|
||||
this.areEqual = false;//meh
|
||||
this.diffs = null;
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
public static Result error(Throwable e) {
|
||||
return new Result(e);
|
||||
}
|
||||
|
||||
public static Result from(String property, boolean areEqual, String message) {
|
||||
if (!areEqual) {
|
||||
if (property.length() > 0) {
|
||||
|
|
@ -1,11 +1,17 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.java;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
class ByteClassLoader extends ClassLoader {
|
||||
/*
|
||||
* common util not for external use
|
||||
*
|
||||
* Loads the class into the jvm, after the user has generated some bytecode
|
||||
*/
|
||||
public class ByteClassLoader extends ClassLoader {
|
||||
|
||||
private final ConcurrentMap<String, Class<?>> classes = new ConcurrentHashMap<>();
|
||||
public final static ByteClassLoader INSTANCE = new ByteClassLoader();
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
51
src/main/java/nl/sander/reflective/java/Java.java
Normal file
51
src/main/java/nl/sander/reflective/java/Java.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package nl.sander.reflective.java;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
* common utils not for external use
|
||||
*/
|
||||
public class Java {
|
||||
|
||||
public static final String INIT = "<init>";
|
||||
public static final String ZERO_ARGS_VOID = "()V";
|
||||
public static final String OBJECT = "Ljava/lang/Object;";
|
||||
|
||||
public static String internalName(String className) {
|
||||
return className.replaceAll("\\.", "/");
|
||||
}
|
||||
public static String internalName(Class<?> type) {
|
||||
return internalName(type.getName());
|
||||
}
|
||||
public static boolean hasArgs(String desc) {
|
||||
return desc.charAt(1) != ')';
|
||||
}
|
||||
|
||||
public static String asProperty(String getter, boolean isRecord) {
|
||||
if (isRecord) {
|
||||
return getter;
|
||||
} else {
|
||||
if (getter.startsWith("get")) {
|
||||
return getter.substring(3, 4).toLowerCase() + getter.substring(4);
|
||||
} else {
|
||||
return getter.substring(2, 3).toLowerCase() + getter.substring(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getReturnType(String desc) {
|
||||
return desc.substring(2);
|
||||
}
|
||||
|
||||
public static ClassReader getClassReader(Object value) throws ClassNotFoundException {
|
||||
ClassReader cr = null;
|
||||
try {
|
||||
cr = new ClassReader(value.getClass().getName());
|
||||
} catch (IOException e) {
|
||||
throw new ClassNotFoundException(value.getClass().getName());
|
||||
}
|
||||
return cr;
|
||||
}
|
||||
}
|
||||
37
src/main/java/nl/sander/reflective/tomap/AbstractToMap.java
Normal file
37
src/main/java/nl/sander/reflective/tomap/AbstractToMap.java
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package nl.sander.reflective.tomap;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractToMap {
|
||||
|
||||
public abstract Map<String, Object> toMap(Object object);
|
||||
|
||||
protected void add(HashMap<String, Object> m, String key, byte b) {
|
||||
m.put(key, b);
|
||||
}
|
||||
|
||||
protected void add(HashMap<String, Object> m, String key, short s) {
|
||||
m.put(key, s);
|
||||
}
|
||||
|
||||
protected void add(HashMap<String, Object> m, String key, int i) {
|
||||
m.put(key, i);
|
||||
}
|
||||
|
||||
protected void add(HashMap<String, Object> m, String key, boolean b) {
|
||||
m.put(key, b);
|
||||
}
|
||||
|
||||
protected void add(HashMap<String, Object> m, String key, float f) {
|
||||
m.put(key, f);
|
||||
}
|
||||
|
||||
protected void add(HashMap<String, Object> m, String key, double b) {
|
||||
m.put(key, b);
|
||||
}
|
||||
|
||||
protected void add(HashMap<String, Object> m, String key, Object o) {
|
||||
m.put(key, o);
|
||||
}
|
||||
}
|
||||
50
src/main/java/nl/sander/reflective/tomap/ToMap.java
Normal file
50
src/main/java/nl/sander/reflective/tomap/ToMap.java
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package nl.sander.reflective.tomap;
|
||||
|
||||
|
||||
import nl.sander.reflective.java.ByteClassLoader;
|
||||
import nl.sander.reflective.java.Java;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* Turns any class (beans with getters/setters and records) into a HashMap.
|
||||
*/
|
||||
public class ToMap {
|
||||
private static final ConcurrentMap<Class<?>, AbstractToMap> cache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* @param value some bean or record (so use wisely if the class is not of that pattern)
|
||||
* @return Map<String, Object>
|
||||
* @throws Exception if the class that you want to mappify somehow can't be read from the classpath
|
||||
*/
|
||||
public static Map<String, Object> map(Object value) throws Exception {
|
||||
try {
|
||||
return cache.computeIfAbsent(value.getClass(), k ->
|
||||
createNew(value)).toMap(value);
|
||||
} catch (RuntimeException e) {
|
||||
throw new Exception(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
private static AbstractToMap createNew(Object value) {
|
||||
try{
|
||||
ClassReader cr = Java.getClassReader(value);
|
||||
ToMapFactory factory = new ToMapFactory();
|
||||
cr.accept(factory, ClassReader.SKIP_FRAMES);
|
||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
|
||||
factory.classNode.accept(classWriter);
|
||||
byte[] byteArray = classWriter.toByteArray();
|
||||
|
||||
ByteClassLoader.INSTANCE.addClass(factory.classNode.name, byteArray);
|
||||
return (AbstractToMap) ByteClassLoader.INSTANCE.loadClass(factory.classNode.name).getConstructor().newInstance();}
|
||||
catch (Exception e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
89
src/main/java/nl/sander/reflective/tomap/ToMapFactory.java
Normal file
89
src/main/java/nl/sander/reflective/tomap/ToMapFactory.java
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package nl.sander.reflective.tomap;
|
||||
|
||||
import nl.sander.reflective.java.Java;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
class ToMapFactory extends ClassVisitor {
|
||||
public static final String SUPER_NAME = Java.internalName(AbstractToMap.class.getName());
|
||||
private boolean isRecord = false;
|
||||
final ClassNode classNode = new ClassNode();
|
||||
|
||||
private String classToMap;
|
||||
|
||||
private MethodNode mappifyMethod;
|
||||
|
||||
|
||||
public ToMapFactory() {
|
||||
super(ASM9);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
if (superName.equals("java/lang/Record")) {
|
||||
isRecord = true;
|
||||
}
|
||||
this.classToMap = name;
|
||||
classNode.name = "ToMap" + UUID.randomUUID();
|
||||
classNode.superName = SUPER_NAME;
|
||||
classNode.version = V11;
|
||||
classNode.access = ACC_PUBLIC;
|
||||
MethodNode constructor = new MethodNode(ACC_PUBLIC, Java.INIT, Java.ZERO_ARGS_VOID, null, null);
|
||||
constructor.instructions.add(new VarInsnNode(ALOAD, 0));
|
||||
constructor.instructions.add(new MethodInsnNode(INVOKESPECIAL, SUPER_NAME, Java.INIT, Java.ZERO_ARGS_VOID));
|
||||
constructor.instructions.add(new InsnNode(RETURN));
|
||||
classNode.methods.add(constructor);
|
||||
|
||||
mappifyMethod = new MethodNode(ACC_PUBLIC,
|
||||
"toMap", "(Ljava/lang/Object;)Ljava/util/Map;", null, null);
|
||||
classNode.methods.add(mappifyMethod);
|
||||
add(new TypeInsnNode(NEW, "java/util/HashMap"));
|
||||
add(new InsnNode(DUP));
|
||||
add(new MethodInsnNode(INVOKESPECIAL, "java/util/HashMap", Java.INIT, Java.ZERO_ARGS_VOID));
|
||||
add(new VarInsnNode(ASTORE, 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String methodname,
|
||||
String desc, String signature, String[] exceptions) {
|
||||
if (!Java.hasArgs(desc) && access == Modifier.PUBLIC && isRecord ||
|
||||
(methodname.startsWith("get") || (methodname.startsWith("is")) && desc.equals("()Z"))) {
|
||||
visitGetter(methodname, Java.asProperty(methodname, isRecord), Java.getReturnType(desc));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void visitGetter(String getterMethodName, String propertyName, String returnType) {
|
||||
add(new VarInsnNode(ALOAD, 0));
|
||||
add(new VarInsnNode(ALOAD, 2));
|
||||
add(new LdcInsnNode(propertyName));
|
||||
add(new VarInsnNode(ALOAD, 1));
|
||||
add(new TypeInsnNode(CHECKCAST, Java.internalName(classToMap)));
|
||||
add(new MethodInsnNode(INVOKEVIRTUAL, classToMap, getterMethodName, "()" + returnType));
|
||||
add(new MethodInsnNode(INVOKEVIRTUAL, classNode.name, "add", "(Ljava/util/HashMap;Ljava/lang/String;"+translate(returnType)+")V"));
|
||||
}
|
||||
|
||||
private String translate(String typeDesc){
|
||||
if (typeDesc.startsWith("L")){
|
||||
return Java.OBJECT;
|
||||
} else {
|
||||
return typeDesc;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
add(new VarInsnNode(ALOAD, 2));
|
||||
add(new InsnNode(ARETURN));
|
||||
}
|
||||
|
||||
private void add(AbstractInsnNode ins) {
|
||||
mappifyMethod.instructions.add(ins);
|
||||
}
|
||||
}
|
||||
15
src/test/java/ExampleMappifier.java
Normal file
15
src/test/java/ExampleMappifier.java
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import nl.sander.reflective.tomap.AbstractToMap;
|
||||
import nl.sander.reflective.compare.PlumBean;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ExampleMappifier extends AbstractToMap {
|
||||
|
||||
public Map<String, Object> toMap(Object o) {
|
||||
HashMap<String, Object> m = new HashMap<>();
|
||||
add(m, "core", ((PlumBean) o).getCore());
|
||||
add(m, "number", ((PlumBean) o).getNumber());
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package nl.sander.apples;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class BytesTest {
|
||||
|
||||
@Test
|
||||
void nilEqualsNil() {
|
||||
assertEquals(Result.SAME, Apples.compare((byte) 0, (byte) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0 != 1"), Apples.compare((byte) 0, (byte) 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void OneNotEqualsNil() {
|
||||
assertEquals(Result.unequal("1 != 0"), Apples.compare((byte) 1, (byte) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilByteNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Byte: 0 != 1"), Apples.compare(Byte.valueOf((byte) 0), (byte) 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneByte() {
|
||||
assertEquals(Result.unequal("0 != java.lang.Byte: 1"), Apples.compare((byte) 0, Byte.valueOf((byte) 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilByte() {
|
||||
assertEquals(Result.unequal("null != java.lang.Byte: 0"), Apples.compare(null, Byte.valueOf((byte) 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0"), Apples.compare(null, (byte) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilByteNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Byte: 0 != null"), Apples.compare(Byte.valueOf((byte) 0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0 != null"), Apples.compare((byte) 0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void byteNotEqualsString() {
|
||||
assertEquals(Result.unequal("0 != \"true\""), Apples.compare((byte) 0, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsByte() {
|
||||
assertEquals(Result.unequal("\"false\" != 0"), Apples.compare("false", (byte) 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package nl.sander.apples;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CharsTest {
|
||||
|
||||
@Test
|
||||
void nilEqualsNil() {
|
||||
assertTrue(Apples.compare((char) 0, (char) 0).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsSome() {
|
||||
assertEquals(Result.unequal("'A' != 'B'"),Apples.compare('A', 'B'));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNil() {
|
||||
assertEquals(Result.unequal("'\\u0001' != '\\u0000'"),Apples.compare((char) 1, (char) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void charEqualsCharacter() {
|
||||
assertTrue(Apples.compare(Character.valueOf('X'), 'X').areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneCharacter() {
|
||||
assertEquals(Result.unequal("'\\u0000' != '\\u0001'"),Apples.compare((char) 0, Character.valueOf((char) 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilCharacter() {
|
||||
assertEquals(Result.unequal("null != '\\u0000'"),Apples.compare(null, Character.valueOf((char) 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsChar() {
|
||||
assertEquals(Result.unequal("null != '\\u0000'"),Apples.compare(null, (char) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilCharacterNotEqualsNull() {
|
||||
assertEquals(Result.unequal("'\\u0000' != null"),Apples.compare(Character.valueOf((char) 0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void charNotEqualsNull() {
|
||||
assertEquals(Result.unequal("'\\u0000' != null"),Apples.compare((char) 0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void charNotEqualsString() {
|
||||
assertEquals(Result.unequal("'\\u0000' != \"true\""),Apples.compare((char)0, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsChar() {
|
||||
assertEquals(Result.unequal("\"false\" != '\\u0000'"),Apples.compare("false", (char)0));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
package nl.sander.apples;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@SuppressWarnings("ConstantValue")
|
||||
class FloatsTest {
|
||||
|
||||
@Test
|
||||
void floatImprecisionLeft() {
|
||||
assertTrue(Apples.compare(2 / 3F, 0.66F, 2).areEqual(), (2 / 3F) + " != " + 0.66F);
|
||||
}
|
||||
|
||||
@Test
|
||||
void floatImprecisionRight() {
|
||||
assertTrue(Apples.compare(0.66F, 2 / 3F, 2).areEqual(), (2 / 3F) + " != " + 0.66F);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFEqualsNilF() {
|
||||
assertTrue(Apples.compare(0F, 0F).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFEqualsNilFloat() {
|
||||
assertTrue(Apples.compare(0F, Float.valueOf(0)).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFEqualsNilL() {
|
||||
assertTrue(Apples.compare(0F, 0L).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilEqualsNilF() {
|
||||
assertTrue(Apples.compare(0L, 0F).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0.0 != 1.0"), Apples.compare(0F, 1F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNull() {
|
||||
assertEquals(Result.unequal("1.0 != 0.0"), Apples.compare(1F, 0F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilByteNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Float: 0.0 != 1.0"), Apples.compare(Float.valueOf(0), 1F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneByte() {
|
||||
assertEquals(Result.unequal("0.0 != java.lang.Float: 1.0"), Apples.compare(0F, Float.valueOf(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilFloat() {
|
||||
assertEquals(Result.unequal("null != java.lang.Float: 0.0"), Apples.compare(null, Float.valueOf(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0.0"), Apples.compare(null, 0F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFloatNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Float: 0.0 != null"), Apples.compare(Float.valueOf(0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0.0 != null"), Apples.compare(0F, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void floatNotEqualsString() {
|
||||
assertEquals(Result.unequal("0.0 != \"true\""), Apples.compare(0F, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsFloat() {
|
||||
assertEquals(Result.unequal("\"false\" != 0.0"), Apples.compare("false", 0F));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
package nl.sander.apples;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class LongsTest {
|
||||
|
||||
@Test
|
||||
void nullEqualsNull() {
|
||||
assertEquals(Result.SAME, Apples.compare(0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0 != 1"), Apples.compare(0, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNull() {
|
||||
assertEquals(Result.unequal("1 != 0"), Apples.compare(1, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilLongNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Long: 0 != 1"), Apples.compare(Long.valueOf(0), 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneLong() {
|
||||
assertEquals(Result.unequal("0 != java.lang.Long: 1"), Apples.compare(0, Long.valueOf(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilEqualsNilLong() {
|
||||
assertTrue(Apples.compare(0, Long.valueOf(0)).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilLong() {
|
||||
assertEquals(Result.unequal("null != java.lang.Long: 0"), Apples.compare(null, Long.valueOf(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0"), Apples.compare(null, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilLongNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Long: 0 != null"), Apples.compare(Long.valueOf(0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0 != null"), Apples.compare(0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void longNotEqualsString() {
|
||||
assertEquals(Result.unequal("0 != \"0\""), Apples.compare(0, "0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsLong() {
|
||||
assertEquals(Result.unequal("\"false\" != 0"), Apples.compare("false", 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
package nl.sander.apples;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ShortsTest {
|
||||
|
||||
@Test
|
||||
void nullEqualsNull() {
|
||||
assertTrue(Apples.compare((short) 0, (short) 0).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullEqualsNullShort() {
|
||||
assertTrue(Apples.compare((short) 0, Short.valueOf((short) 0)).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullShortEqualsNull() {
|
||||
assertTrue(Apples.compare(Short.valueOf((short) 0), (short) 0).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0 != 1"), Apples.compare((short) 0, (short) 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNull() {
|
||||
assertEquals(Result.unequal("1 != 0"), Apples.compare((short) 1, (short) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilshortNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Short: 0 != 1"), Apples.compare(Short.valueOf((short) 0), (short) 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneshort() {
|
||||
assertEquals(Result.unequal("0 != java.lang.Short: 1"), Apples.compare((short) 0, Short.valueOf((short) 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilshort() {
|
||||
assertEquals(Result.unequal("null != java.lang.Short: 0"), Apples.compare(null, Short.valueOf((short) 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0"), Apples.compare(null, (short) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilshortNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Short: 0 != null"), Apples.compare(Short.valueOf((short) 0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0 != null"), Apples.compare((short) 0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shortNotEqualsString() {
|
||||
assertEquals(Result.unequal("0 != \"true\""), Apples.compare((short) 0, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsshort() {
|
||||
assertEquals(Result.unequal("\"false\" != 0"), Apples.compare("false", (short) 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ public class BeansTest {
|
|||
|
||||
@Test
|
||||
void testBeans() {
|
||||
Result comparison = Apples.compare(new PlumBean("small", "red", true, 1, 1.0F, Storage.HIGH, (byte) 1, List.of(new Shop("tesco"))),
|
||||
Result comparison = Compare.compare(new PlumBean("small", "red", true, 1, 1.0F, Storage.HIGH, (byte) 1, List.of(new Shop("tesco"))),
|
||||
new PlumBean("large", "green", true, 1, 1.0F, Storage.LOW, (byte) 1, List.of(new Shop("asda"))));
|
||||
|
||||
assertFalse(comparison.areEqual());
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -8,103 +8,103 @@ class BooleansTest {
|
|||
|
||||
@Test
|
||||
void falseEqualsFalse() {
|
||||
assertTrue(Apples.compare(false, false).areEqual());
|
||||
assertTrue(Compare.compare(false, false).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void falseEqualsBooleanFalse() {
|
||||
assertTrue(Apples.compare(false, Boolean.FALSE).areEqual());
|
||||
assertTrue(Compare.compare(false, Boolean.FALSE).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void trueEqualsBooleanTrue() {
|
||||
assertTrue(Apples.compare(true, Boolean.TRUE).areEqual());
|
||||
assertTrue(Compare.compare(true, Boolean.TRUE).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void trueEqualsTrue() {
|
||||
assertTrue(Apples.compare(true, true).areEqual());
|
||||
assertTrue(Compare.compare(true, true).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void falseNotEqualsTrue() {
|
||||
assertEquals(Result.unequal("false != true"), Apples.compare(false, true));
|
||||
assertEquals(Result.unequal("false != true"), Compare.compare(false, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void trueNotEqualsFalse() {
|
||||
assertEquals(Result.unequal("true != false"), Apples.compare(true, false));
|
||||
assertEquals(Result.unequal("true != false"), Compare.compare(true, false));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void falseNotEqualsTrueBoolean() {
|
||||
assertEquals(Result.unequal("false != java.lang.Boolean: true"), Apples.compare(false, Boolean.valueOf(true)));
|
||||
assertEquals(Result.unequal("false != java.lang.Boolean: true"), Compare.compare(false, Boolean.valueOf(true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void trueNotEqualsFalseBoolean() {
|
||||
assertEquals(Result.unequal("true != java.lang.Boolean: false"), Apples.compare(true, Boolean.valueOf(false)));
|
||||
assertEquals(Result.unequal("true != java.lang.Boolean: false"), Compare.compare(true, Boolean.valueOf(false)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void falseBooleanNotEqualsTrue() {
|
||||
assertEquals(Result.unequal("java.lang.Boolean: false != true"), Apples.compare(Boolean.valueOf(false), true));
|
||||
assertEquals(Result.unequal("java.lang.Boolean: false != true"), Compare.compare(Boolean.valueOf(false), true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void trueBooleanNotEqualsFalse() {
|
||||
assertEquals(Result.unequal("java.lang.Boolean: true != false"), Apples.compare(Boolean.valueOf(true), false));
|
||||
assertEquals(Result.unequal("java.lang.Boolean: true != false"), Compare.compare(Boolean.valueOf(true), false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsTrue() {
|
||||
assertEquals(Result.unequal("null != true"), Apples.compare(null, true));
|
||||
assertEquals(Result.unequal("null != true"), Compare.compare(null, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsFalse() {
|
||||
assertEquals(Result.unequal("null != false"), Apples.compare(null, false));
|
||||
assertEquals(Result.unequal("null != false"), Compare.compare(null, false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void trueNotEqualsNull() {
|
||||
assertEquals(Result.unequal("true != null"), Apples.compare(true, null));
|
||||
assertEquals(Result.unequal("true != null"), Compare.compare(true, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void falseNotEqualsNull() {
|
||||
assertEquals(Result.unequal("false != null"), Apples.compare(false, null));
|
||||
assertEquals(Result.unequal("false != null"), Compare.compare(false, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void trueNotEqualsString() {
|
||||
assertEquals(Result.unequal("true != \"true\""), Apples.compare(true, "true"));
|
||||
assertEquals(Result.unequal("true != \"true\""), Compare.compare(true, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsFalse() {
|
||||
assertEquals(Result.unequal("\"false\" != false"), Apples.compare("false", false));
|
||||
assertEquals(Result.unequal("\"false\" != false"), Compare.compare("false", false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsTrueBoolean() {
|
||||
assertEquals(Result.unequal("null != java.lang.Boolean: true"), Apples.compare(null, Boolean.TRUE));
|
||||
assertEquals(Result.unequal("null != java.lang.Boolean: true"), Compare.compare(null, Boolean.TRUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsFalseBoolean() {
|
||||
assertEquals(Result.unequal("null != java.lang.Boolean: false"), Apples.compare(null, Boolean.FALSE));
|
||||
assertEquals(Result.unequal("null != java.lang.Boolean: false"), Compare.compare(null, Boolean.FALSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void trueBooleanNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Boolean: true != null"), Apples.compare(Boolean.TRUE, null));
|
||||
assertEquals(Result.unequal("java.lang.Boolean: true != null"), Compare.compare(Boolean.TRUE, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void falseBooleanNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Boolean: false != null"), Apples.compare(Boolean.FALSE, null));
|
||||
assertEquals(Result.unequal("java.lang.Boolean: false != null"), Compare.compare(Boolean.FALSE, null));
|
||||
}
|
||||
|
||||
|
||||
63
src/test/java/nl/sander/reflective/compare/BytesTest.java
Normal file
63
src/test/java/nl/sander/reflective/compare/BytesTest.java
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class BytesTest {
|
||||
|
||||
@Test
|
||||
void nilEqualsNil() {
|
||||
assertEquals(Result.SAME, Compare.compare((byte) 0, (byte) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0 != 1"), Compare.compare((byte) 0, (byte) 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void OneNotEqualsNil() {
|
||||
assertEquals(Result.unequal("1 != 0"), Compare.compare((byte) 1, (byte) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilByteNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Byte: 0 != 1"), Compare.compare(Byte.valueOf((byte) 0), (byte) 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneByte() {
|
||||
assertEquals(Result.unequal("0 != java.lang.Byte: 1"), Compare.compare((byte) 0, Byte.valueOf((byte) 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilByte() {
|
||||
assertEquals(Result.unequal("null != java.lang.Byte: 0"), Compare.compare(null, Byte.valueOf((byte) 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0"), Compare.compare(null, (byte) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilByteNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Byte: 0 != null"), Compare.compare(Byte.valueOf((byte) 0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0 != null"), Compare.compare((byte) 0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void byteNotEqualsString() {
|
||||
assertEquals(Result.unequal("0 != \"true\""), Compare.compare((byte) 0, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsByte() {
|
||||
assertEquals(Result.unequal("\"false\" != 0"), Compare.compare("false", (byte) 0));
|
||||
}
|
||||
}
|
||||
63
src/test/java/nl/sander/reflective/compare/CharsTest.java
Normal file
63
src/test/java/nl/sander/reflective/compare/CharsTest.java
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CharsTest {
|
||||
|
||||
@Test
|
||||
void nilEqualsNil() {
|
||||
assertTrue(Compare.compare((char) 0, (char) 0).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsSome() {
|
||||
assertEquals(Result.unequal("'A' != 'B'"), Compare.compare('A', 'B'));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNil() {
|
||||
assertEquals(Result.unequal("'\\u0001' != '\\u0000'"), Compare.compare((char) 1, (char) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void charEqualsCharacter() {
|
||||
assertTrue(Compare.compare(Character.valueOf('X'), 'X').areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneCharacter() {
|
||||
assertEquals(Result.unequal("'\\u0000' != '\\u0001'"), Compare.compare((char) 0, Character.valueOf((char) 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilCharacter() {
|
||||
assertEquals(Result.unequal("null != '\\u0000'"), Compare.compare(null, Character.valueOf((char) 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsChar() {
|
||||
assertEquals(Result.unequal("null != '\\u0000'"), Compare.compare(null, (char) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilCharacterNotEqualsNull() {
|
||||
assertEquals(Result.unequal("'\\u0000' != null"), Compare.compare(Character.valueOf((char) 0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void charNotEqualsNull() {
|
||||
assertEquals(Result.unequal("'\\u0000' != null"), Compare.compare((char) 0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void charNotEqualsString() {
|
||||
assertEquals(Result.unequal("'\\u0000' != \"true\""), Compare.compare((char) 0, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsChar() {
|
||||
assertEquals(Result.unequal("\"false\" != '\\u0000'"), Compare.compare("false", (char) 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class DifferentTypesTest {
|
||||
@Test
|
||||
void testAppleAndOrange() {
|
||||
assertTrue(Compare.any(new Apple("orange"), new Orange("orange")).areEqual());
|
||||
}
|
||||
|
||||
class Apple {
|
||||
final String color;
|
||||
|
||||
Apple(String color) {
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
class Orange {
|
||||
final String color;
|
||||
|
||||
Orange(String color) {
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -8,77 +8,77 @@ class DoublesTest {
|
|||
|
||||
@Test
|
||||
void floatImprecisionLeft() {
|
||||
assertTrue(Apples.compare(2 / 3.0, 0.66, 2).areEqual(), (2 / 3) + " != " + 0.66);
|
||||
assertTrue(Compare.compare(2 / 3.0, 0.66, 2).areEqual(), (2 / 3) + " != " + 0.66);
|
||||
}
|
||||
|
||||
@Test
|
||||
void floatImprecisionRight() {
|
||||
assertTrue(Apples.compare(0.66, 2 / 3D, 2).areEqual(), (2 / 3D) + " != " + 0.66);
|
||||
assertTrue(Compare.compare(0.66, 2 / 3D, 2).areEqual(), (2 / 3D) + " != " + 0.66);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFEqualsNilF() {
|
||||
assertTrue(Apples.compare(0.0, .0).areEqual());
|
||||
assertTrue(Compare.compare(0.0, .0).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFEqualsNilL() {
|
||||
assertTrue(Apples.compare(0.0, 0L).areEqual());
|
||||
assertTrue(Compare.compare(0.0, 0L).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilEqualsNilF() {
|
||||
assertTrue(Apples.compare(0L, 0.0).areEqual());
|
||||
assertTrue(Compare.compare(0L, 0.0).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0.0 != 1.0"), Apples.compare(0.0, 1.0F));
|
||||
assertEquals(Result.unequal("0.0 != 1.0"), Compare.compare(0.0, 1.0F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNull() {
|
||||
assertEquals(Result.unequal("1.0 != 0.0"), Apples.compare(1.0, .0));
|
||||
assertEquals(Result.unequal("1.0 != 0.0"), Compare.compare(1.0, .0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilDoubleNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Double: 0.0 != 1.0"), Apples.compare(Double.valueOf(0), 1F));
|
||||
assertEquals(Result.unequal("java.lang.Double: 0.0 != 1.0"), Compare.compare(Double.valueOf(0), 1F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneDouble() {
|
||||
assertEquals(Result.unequal("0.0 != java.lang.Double: 1.0"), Apples.compare(0F, Double.valueOf(1)));
|
||||
assertEquals(Result.unequal("0.0 != java.lang.Double: 1.0"), Compare.compare(0F, Double.valueOf(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilDouble() {
|
||||
assertEquals(Result.unequal("null != java.lang.Double: 0.0"), Apples.compare(null, Double.valueOf(0)));
|
||||
assertEquals(Result.unequal("null != java.lang.Double: 0.0"), Compare.compare(null, Double.valueOf(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0.0"), Apples.compare(null, .0));
|
||||
assertEquals(Result.unequal("null != 0.0"), Compare.compare(null, .0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilDoubleNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Double: 0.0 != null"), Apples.compare(Double.valueOf(0), null));
|
||||
assertEquals(Result.unequal("java.lang.Double: 0.0 != null"), Compare.compare(Double.valueOf(0), null));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0.0 != null"), Apples.compare(.0, null));
|
||||
assertEquals(Result.unequal("0.0 != null"), Compare.compare(.0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doubleNotEqualsString() {
|
||||
assertEquals(Result.unequal("0.0 != \"0\""), Apples.compare(.0, "0"));
|
||||
assertEquals(Result.unequal("0.0 != \"0\""), Compare.compare(.0, "0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsDouble() {
|
||||
assertEquals(Result.unequal("\"0\" != 0.0"), Apples.compare("0", .0));
|
||||
assertEquals(Result.unequal("\"0\" != 0.0"), Compare.compare("0", .0));
|
||||
}
|
||||
}
|
||||
88
src/test/java/nl/sander/reflective/compare/FloatsTest.java
Normal file
88
src/test/java/nl/sander/reflective/compare/FloatsTest.java
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class FloatsTest {
|
||||
|
||||
@Test
|
||||
void floatImprecisionLeft() {
|
||||
assertTrue(Compare.compare(2 / 3F, 0.66F, 2).areEqual(), (2 / 3F) + " != " + 0.66F);
|
||||
}
|
||||
|
||||
@Test
|
||||
void floatImprecisionRight() {
|
||||
assertTrue(Compare.compare(0.66F, 2 / 3F, 2).areEqual(), (2 / 3F) + " != " + 0.66F);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFEqualsNilF() {
|
||||
assertTrue(Compare.compare(0F, 0F).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFEqualsNilFloat() {
|
||||
assertTrue(Compare.compare(0F, Float.valueOf(0)).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFEqualsNilL() {
|
||||
assertTrue(Compare.compare(0F, 0L).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilEqualsNilF() {
|
||||
assertTrue(Compare.compare(0L, 0F).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0.0 != 1.0"), Compare.compare(0F, 1F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNull() {
|
||||
assertEquals(Result.unequal("1.0 != 0.0"), Compare.compare(1F, 0F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilByteNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Float: 0.0 != 1.0"), Compare.compare(Float.valueOf(0), 1F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneByte() {
|
||||
assertEquals(Result.unequal("0.0 != java.lang.Float: 1.0"), Compare.compare(0F, Float.valueOf(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilFloat() {
|
||||
assertEquals(Result.unequal("null != java.lang.Float: 0.0"), Compare.compare(null, Float.valueOf(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0.0"), Compare.compare(null, 0F));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilFloatNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Float: 0.0 != null"), Compare.compare(Float.valueOf(0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0.0 != null"), Compare.compare(0F, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void floatNotEqualsString() {
|
||||
assertEquals(Result.unequal("0.0 != \"true\""), Compare.compare(0F, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsFloat() {
|
||||
assertEquals(Result.unequal("\"false\" != 0.0"), Compare.compare("false", 0F));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -8,66 +8,66 @@ class IntsTest {
|
|||
|
||||
@Test
|
||||
void nilEqualsNil() {
|
||||
assertEquals(Result.SAME, Apples.compare(0, 0));
|
||||
assertEquals(Result.SAME, Compare.compare(0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilEqualsNilInteger() {
|
||||
assertEquals(Result.SAME, Apples.compare(0, Integer.valueOf(0)));
|
||||
assertEquals(Result.SAME, Compare.compare(0, Integer.valueOf(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilIntegerEqualsNil() {
|
||||
assertEquals(Result.SAME, Apples.compare(Integer.valueOf(0), 0));
|
||||
assertEquals(Result.SAME, Compare.compare(Integer.valueOf(0), 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0 != 1"), Apples.compare(0, 1));
|
||||
assertEquals(Result.unequal("0 != 1"), Compare.compare(0, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNull() {
|
||||
assertEquals(Result.unequal("1 != 0"), Apples.compare(1, 0));
|
||||
assertEquals(Result.unequal("1 != 0"), Compare.compare(1, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilByteNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Integer: 0 != 1"), Apples.compare(Integer.valueOf(0), 1));
|
||||
assertEquals(Result.unequal("java.lang.Integer: 0 != 1"), Compare.compare(Integer.valueOf(0), 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneByte() {
|
||||
assertEquals(Result.unequal("0 != java.lang.Integer: 1"), Apples.compare(0, Integer.valueOf(1)));
|
||||
assertEquals(Result.unequal("0 != java.lang.Integer: 1"), Compare.compare(0, Integer.valueOf(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilByte() {
|
||||
assertEquals(Result.unequal("null != java.lang.Integer: 0"), Apples.compare(null, Integer.valueOf(0)));
|
||||
assertEquals(Result.unequal("null != java.lang.Integer: 0"), Compare.compare(null, Integer.valueOf(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0"), Apples.compare(null, 0));
|
||||
assertEquals(Result.unequal("null != 0"), Compare.compare(null, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilByteNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Integer: 0 != null"), Apples.compare(Integer.valueOf(0), null));
|
||||
assertEquals(Result.unequal("java.lang.Integer: 0 != null"), Compare.compare(Integer.valueOf(0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0 != null"), Apples.compare(0, null));
|
||||
assertEquals(Result.unequal("0 != null"), Compare.compare(0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void intNotEqualsString() {
|
||||
assertEquals(Result.unequal("0 != \"true\""), Apples.compare(0, "true"));
|
||||
assertEquals(Result.unequal("0 != \"true\""), Compare.compare(0, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsInt() {
|
||||
assertEquals(Result.unequal("\"0\" != 0"), Apples.compare("0", 0));
|
||||
assertEquals(Result.unequal("\"0\" != 0"), Compare.compare("0", 0));
|
||||
}
|
||||
}
|
||||
68
src/test/java/nl/sander/reflective/compare/LongsTest.java
Normal file
68
src/test/java/nl/sander/reflective/compare/LongsTest.java
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class LongsTest {
|
||||
|
||||
@Test
|
||||
void nullEqualsNull() {
|
||||
assertEquals(Result.SAME, Compare.compare(0, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0 != 1"), Compare.compare(0, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNull() {
|
||||
assertEquals(Result.unequal("1 != 0"), Compare.compare(1, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilLongNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Long: 0 != 1"), Compare.compare(Long.valueOf(0), 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneLong() {
|
||||
assertEquals(Result.unequal("0 != java.lang.Long: 1"), Compare.compare(0, Long.valueOf(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilEqualsNilLong() {
|
||||
assertTrue(Compare.compare(0, Long.valueOf(0)).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilLong() {
|
||||
assertEquals(Result.unequal("null != java.lang.Long: 0"), Compare.compare(null, Long.valueOf(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0"), Compare.compare(null, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilLongNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Long: 0 != null"), Compare.compare(Long.valueOf(0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0 != null"), Compare.compare(0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void longNotEqualsString() {
|
||||
assertEquals(Result.unequal("0 != \"0\""), Compare.compare(0, "0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsLong() {
|
||||
assertEquals(Result.unequal("\"false\" != 0"), Compare.compare("false", 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -11,32 +11,32 @@ class ObjectsTest {
|
|||
|
||||
@Test
|
||||
void nullEqualsNull() {
|
||||
assertTrue(Apples.compare(null, null).areEqual());
|
||||
assertTrue(Compare.compare(null, null).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsSome() {
|
||||
assertEquals(Result.unequal("null != \"some\""), Apples.compare(null, "some"));
|
||||
assertEquals(Result.unequal("null != \"some\""), Compare.compare(null, "some"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNull() {
|
||||
assertEquals(Result.unequal("\"some\" != null"), Apples.compare("some", null));
|
||||
assertEquals(Result.unequal("\"some\" != null"), Compare.compare("some", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentClass() {
|
||||
assertEquals(Result.unequal("\"1\" != java.lang.Integer: 1"), Apples.compare("1", Integer.valueOf(1)));
|
||||
assertEquals(Result.unequal("\"1\" != java.lang.Integer: 1"), Compare.compare("1", Integer.valueOf(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sameKeysAndValues() {
|
||||
assertTrue(Apples.compare("map", Map.of("a", 1, "b", 2), Map.of("b", 2, "a", 1)).areEqual());
|
||||
assertTrue(Compare.compare("map", Map.of("a", 1, "b", 2), Map.of("b", 2, "a", 1)).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void differentKeysAndValues() {
|
||||
Result result = Apples.compare("map", Map.of("a", 2, "b", 1), Map.of("b", 2, "a", 1));
|
||||
Result result = Compare.compare("map", Map.of("a", 2, "b", 1), Map.of("b", 2, "a", 1));
|
||||
assertFalse(result.areEqual());
|
||||
assertTrue(result.getDiffs().contains("for map[b]: 1 != 2"));
|
||||
assertTrue(result.getDiffs().contains("for map[a]: 2 != 1"));
|
||||
|
|
@ -44,14 +44,14 @@ class ObjectsTest {
|
|||
|
||||
@Test
|
||||
void bigDecimals() {
|
||||
Result result = Apples.compare(BigDecimal.valueOf(0), BigDecimal.valueOf(1));
|
||||
Result result = Compare.compare(BigDecimal.valueOf(0), BigDecimal.valueOf(1));
|
||||
assertFalse(result.areEqual());
|
||||
assertEquals("0 != 1", result.getDiffs().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void enums() {
|
||||
Result result = Apples.compare(Storage.HIGH, Storage.LOW);
|
||||
Result result = Compare.compare(Storage.HIGH, Storage.LOW);
|
||||
assertFalse(result.areEqual());
|
||||
assertEquals("HIGH != LOW", result.getDiffs().get(0));
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
public class Shop {
|
||||
private final String name;
|
||||
73
src/test/java/nl/sander/reflective/compare/ShortsTest.java
Normal file
73
src/test/java/nl/sander/reflective/compare/ShortsTest.java
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ShortsTest {
|
||||
|
||||
@Test
|
||||
void nullEqualsNull() {
|
||||
assertTrue(Compare.compare((short) 0, (short) 0).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullEqualsNullShort() {
|
||||
assertTrue(Compare.compare((short) 0, Short.valueOf((short) 0)).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullShortEqualsNull() {
|
||||
assertTrue(Compare.compare(Short.valueOf((short) 0), (short) 0).areEqual());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsSome() {
|
||||
assertEquals(Result.unequal("0 != 1"), Compare.compare((short) 0, (short) 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void SomeNotEqualsNull() {
|
||||
assertEquals(Result.unequal("1 != 0"), Compare.compare((short) 1, (short) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilshortNotEqualsOne() {
|
||||
assertEquals(Result.unequal("java.lang.Short: 0 != 1"), Compare.compare(Short.valueOf((short) 0), (short) 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsOneshort() {
|
||||
assertEquals(Result.unequal("0 != java.lang.Short: 1"), Compare.compare((short) 0, Short.valueOf((short) 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNilshort() {
|
||||
assertEquals(Result.unequal("null != java.lang.Short: 0"), Compare.compare(null, Short.valueOf((short) 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullNotEqualsNil() {
|
||||
assertEquals(Result.unequal("null != 0"), Compare.compare(null, (short) 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilshortNotEqualsNull() {
|
||||
assertEquals(Result.unequal("java.lang.Short: 0 != null"), Compare.compare(Short.valueOf((short) 0), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void nilNotEqualsNull() {
|
||||
assertEquals(Result.unequal("0 != null"), Compare.compare((short) 0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shortNotEqualsString() {
|
||||
assertEquals(Result.unequal("0 != \"true\""), Compare.compare((short) 0, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void StringNotEqualsshort() {
|
||||
assertEquals(Result.unequal("\"false\" != 0"), Compare.compare("false", (short) 0));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
public enum Storage {
|
||||
HIGH,
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package nl.sander.apples;
|
||||
package nl.sander.reflective.compare;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -8,6 +8,6 @@ class StringTest {
|
|||
|
||||
@Test
|
||||
void test() {
|
||||
assertTrue(Apples.compare("left", "left").areEqual());
|
||||
assertTrue(Compare.compare("left", "left").areEqual());
|
||||
}
|
||||
}
|
||||
30
src/test/java/nl/sander/reflective/tomap/ToMapTest.java
Normal file
30
src/test/java/nl/sander/reflective/tomap/ToMapTest.java
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package nl.sander.reflective.tomap;
|
||||
|
||||
import nl.sander.reflective.compare.PlumBean;
|
||||
import nl.sander.reflective.compare.Shop;
|
||||
import nl.sander.reflective.compare.Storage;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class ToMapTest {
|
||||
@Test
|
||||
void testBeans() throws Exception {
|
||||
Map<String,Object> map = ToMap.map(new PlumBean("small", "red", true, 1, 1.0F, Storage.HIGH, (byte) 1, List.of(new Shop("tesco"))));
|
||||
assertEquals("small", map.get("core"));
|
||||
assertEquals("red", map.get("peel"));
|
||||
assertEquals(true, map.get("juicy"));
|
||||
assertEquals(1, map.get("number"));
|
||||
assertEquals(1.0F, map.get("price"));
|
||||
assertEquals(Storage.HIGH, map.get("storage"));
|
||||
assertEquals((byte)1, map.get("cores"));
|
||||
Object shops = map.get("shops");
|
||||
assertTrue(shops instanceof List);
|
||||
List<Shop> shopsList = (List<Shop>) shops;
|
||||
assertEquals(1, shopsList.size());
|
||||
assertEquals("tesco", shopsList.get(0).getName());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue