aboutsummaryrefslogtreecommitdiff
path: root/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java')
-rw-r--r--src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
new file mode 100644
index 0000000..f31ec65
--- /dev/null
+++ b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
@@ -0,0 +1,127 @@
+package org.zwobble.couscous.tests;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.function.Function;
+import java.util.stream.IntStream;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.zwobble.couscous.ast.AnnotationNode;
+import org.zwobble.couscous.util.ExtraArrays;
+
+import com.google.common.base.Joiner;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.zwobble.couscous.util.ExtraArrays.stream;
+
+@RunWith(Parameterized.class)
+public class ValueObjectTests {
+ private final Class<?> clazz;
+
+ public ValueObjectTests(Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ @Parameters(name="{0} is value object")
+ public static Iterable<Object[]> valueObjectTypes() {
+ return asList(new Object[][] {
+ {AnnotationNode.class}
+ });
+ }
+
+ @Test
+ public <T> void toStringIncludesAllFields() {
+ GeneratedValue value = generateValue(clazz, ValueObjectTests::generateInstance);
+ Field[] fields = clazz.getDeclaredFields();
+ Object[] fieldStrings = IntStream.range(0, fields.length)
+ .mapToObj(index -> String.format("%s=%s", fields[index].getName(), value.arguments[index]))
+ .toArray();
+ assertEquals(
+ String.format("%s(%s)",
+ clazz.getSimpleName(),
+ Joiner.on(", ").join(fieldStrings)),
+ value.instance.toString());
+ }
+
+ @Test
+ public void equalityIncludesAllFields() {
+ assertEquals(generateInstance(clazz), generateInstance(clazz));
+ assertNotEquals(
+ generateFirstInstance(clazz),
+ generateSecondInstance(clazz));
+ }
+
+ @Test
+ public void hashCodeIncludesAllFields() {
+ assertEquals(generateInstance(clazz).hashCode(), generateInstance(clazz).hashCode());
+ assertNotEquals(
+ generateFirstInstance(clazz).hashCode(),
+ generateSecondInstance(clazz).hashCode());
+ }
+
+ private static Object generateFirstInstance(Class<?> type) {
+ if (type.equals(String.class)) {
+ return "[string 1]";
+ } else {
+ return generateValue(type, ValueObjectTests::generateFirstInstance).instance;
+ }
+ }
+
+ private static Object generateSecondInstance(Class<?> type) {
+ if (type.equals(String.class)) {
+ return "[string ]";
+ } else {
+ return generateValue(type, ValueObjectTests::generateSecondInstance).instance;
+ }
+ }
+
+ private static Object generateInstance(Class<?> type) {
+ if (type.equals(String.class)) {
+ return "[string]";
+ } else {
+ return generateValue(type, ValueObjectTests::generateInstance).instance;
+ }
+ }
+
+ private static GeneratedValue generateValue(Class<?> type, Function<Class<?>, Object> generate) {
+ try {
+ Field[] fields = type.getDeclaredFields();
+ Class<?>[] fieldTypes = ExtraArrays.map(fields, field -> field.getType())
+ .toArray(Class<?>[]::new);
+ Method constructor = findStaticConstructor(type, fieldTypes);
+ Object[] arguments = ExtraArrays.map(fieldTypes, fieldType -> generate.apply(fieldType))
+ .toArray(Object[]::new);
+ Object instance = constructor.invoke(null, arguments);
+ return new GeneratedValue(instance, arguments);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static Method findStaticConstructor(Class<?> type, Class<?>[] fieldTypes) {
+ return stream(type.getDeclaredMethods())
+ .filter(method -> isStaticConstructor(type, fieldTypes, method))
+ .findAny()
+ .orElseThrow(() -> new RuntimeException("Could not find static constructor for " + type));
+ }
+
+ private static boolean isStaticConstructor(Class<?> type, Class<?>[] fieldTypes, Method method) {
+ return method.getReturnType().equals(type) &&
+ asList(fieldTypes).equals(asList(method.getParameterTypes()));
+ }
+
+ private static class GeneratedValue {
+ private final Object instance;
+ private final Object[] arguments;
+
+ public GeneratedValue(Object value, Object[] arguments) {
+ this.instance = value;
+ this.arguments = arguments;
+ }
+ }
+}