info.javaspec.spec.SpecFactory Maven / Gradle / Ivy
package info.javaspec.spec;
import info.javaspec.context.AmbiguousFixture;
import info.javaspec.context.Context;
import info.javaspec.dsl.Because;
import info.javaspec.dsl.Cleanup;
import info.javaspec.dsl.Establish;
import info.javaspec.dsl.It;
import info.javaspec.util.ReflectionBasedFactory;
import info.javaspec.util.ReflectionUtil;
import org.junit.runner.Description;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
public class SpecFactory extends ReflectionBasedFactory {
private final Context context;
public SpecFactory(Context context) {
this.context = context;
}
public void addSpecsFromClass(Class> source) {
readDeclaredItFields(source)
.map(this::create)
.forEach(context::addSpec);
}
public Spec create(Field it) {
String id = String.format("%s#%s", context.getId(), it.getName());
Description description = context.describeSpec(id, identifierToDisplayName(it.getName()));
List beforeFields = readBeforeSpecFields(it.getDeclaringClass());
List afterFields = readAfterSpecFields(it.getDeclaringClass());
return new FieldSpec(id, description, it, beforeFields, afterFields);
}
private List readBeforeSpecFields(Class> assertionClass) {
LinkedList fields = new LinkedList<>();
Consumer prependToFields = x -> fields.add(0, x);
for(Class> c = assertionClass; c != null; c = c.getEnclosingClass()) {
onlyDeclaredField(c, Because.class).ifPresent(prependToFields);
onlyDeclaredField(c, Establish.class).ifPresent(prependToFields);
}
return fields;
}
private List readAfterSpecFields(Class> assertionClass) {
List fields = new LinkedList<>();
for(Class> c = assertionClass; c != null; c = c.getEnclosingClass())
onlyDeclaredField(c, Cleanup.class).ifPresent(fields::add);
return fields;
}
private static Optional onlyDeclaredField(Class> context, Class> fieldType) {
List fields = readDeclaredFields(context, fieldType).limit(2).collect(toList());
switch(fields.size()) {
case 0: return Optional.empty();
case 1: return Optional.of(fields.get(0));
default: throw AmbiguousFixture.forFieldOfType(fieldType, context);
}
}
private static Stream readDeclaredItFields(Class> contextClass) {
return readDeclaredFields(contextClass, It.class);
}
private static Stream readDeclaredFields(Class> contextClass, Class> fieldType) {
Predicate isInstanceField = x -> !Modifier.isStatic(x.getModifiers());
return ReflectionUtil.fieldsOfType(fieldType, contextClass).filter(isInstanceField);
}
}