aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/couscous/util/ExtraArrays.java16
-rw-r--r--src/test/java/org/zwobble/couscous/tests/AnnotationNodeTests.java80
2 files changed, 96 insertions, 0 deletions
diff --git a/src/main/java/org/zwobble/couscous/util/ExtraArrays.java b/src/main/java/org/zwobble/couscous/util/ExtraArrays.java
new file mode 100644
index 0000000..c4ebc57
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/util/ExtraArrays.java
@@ -0,0 +1,16 @@
+package org.zwobble.couscous.util;
+
+import java.util.Arrays;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+public class ExtraArrays {
+ public static <T, R> Stream<R> map(T[] array, Function<T, R> function) {
+ return stream(array).map(function);
+ }
+
+ public static <T> Stream<T> stream(T[] array) {
+ return StreamSupport.stream(Arrays.spliterator(array), false);
+ }
+}
diff --git a/src/test/java/org/zwobble/couscous/tests/AnnotationNodeTests.java b/src/test/java/org/zwobble/couscous/tests/AnnotationNodeTests.java
new file mode 100644
index 0000000..2eb8d9c
--- /dev/null
+++ b/src/test/java/org/zwobble/couscous/tests/AnnotationNodeTests.java
@@ -0,0 +1,80 @@
+package org.zwobble.couscous.tests;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.stream.IntStream;
+
+import org.junit.Test;
+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.zwobble.couscous.util.ExtraArrays.stream;
+
+public class AnnotationNodeTests {
+ @Test
+ public void annotationNodeIsValueObject() throws Exception {
+ assertIsValueObject(AnnotationNode.class);
+ }
+
+ private <T> void assertIsValueObject(Class<T> clazz) throws Exception {
+ GeneratedValue value = generateValue(clazz);
+ 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());
+ }
+
+ private GeneratedValue generateValue(Class<?> type) {
+ 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 -> generateInstance(fieldType))
+ .toArray(Object[]::new);
+ Object instance = constructor.invoke(null, arguments);
+ return new GeneratedValue(instance, arguments);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Object generateInstance(Class<?> type) {
+ if (type.equals(String.class)) {
+ return "[string]";
+ } else {
+ return generateValue(type).instance;
+ }
+ }
+
+ private 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 boolean isStaticConstructor(Class<?> type, Class<?>[] fieldTypes, Method method) {
+ return method.getReturnType().equals(type) &&
+ asList(fieldTypes).equals(asList(method.getParameterTypes()));
+ }
+
+ private class GeneratedValue {
+ private final Object instance;
+ private final Object[] arguments;
+
+ public GeneratedValue(Object value, Object[] arguments) {
+ this.instance = value;
+ this.arguments = arguments;
+ }
+ }
+}