Skip to content

Commit

Permalink
#23 evaluate result/argument annotations (example @SkipChecks)
Browse files Browse the repository at this point in the history
  • Loading branch information
almondtools committed Apr 7, 2017
1 parent f073e2f commit c08f7dc
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 144 deletions.
25 changes: 15 additions & 10 deletions src/main/java/net/amygdalum/testrecorder/TestGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@
import net.amygdalum.testrecorder.deserializers.matcher.MatcherGenerators;
import net.amygdalum.testrecorder.util.ExpectedOutput;
import net.amygdalum.testrecorder.util.IORecorder;
import net.amygdalum.testrecorder.util.Pair;
import net.amygdalum.testrecorder.util.RecordInput;
import net.amygdalum.testrecorder.util.RecordOutput;
import net.amygdalum.testrecorder.util.SetupInput;
import net.amygdalum.testrecorder.util.Throwables;
import net.amygdalum.testrecorder.util.Triple;
import net.amygdalum.testrecorder.values.SerializedField;
import net.amygdalum.testrecorder.values.SerializedInput;
import net.amygdalum.testrecorder.values.SerializedOutput;
Expand Down Expand Up @@ -436,11 +438,12 @@ public MethodGenerator generateArrange() {
this.base = setupThis.isStored()
? setupThis.getValue()
: assign(snapshot.getSetupThis().getType(), setupThis.getValue());
this.args = IntStream.range(0, setupArgs.size())
.mapToObj(i -> setupArgs.get(i).isStored()
? setupArgs.get(i).getValue()
: assign(snapshotSetupArgs[i].value.getResultType(), setupArgs.get(i).getValue()))
.collect(toList());
Pair<Computation, AnnotatedValue>[] arguments = Pair.zip(setupArgs.toArray(new Computation[0]), snapshotSetupArgs);
this.args = Stream.of(arguments)
.map(arg -> arg.getElement1().isStored()
? arg.getElement1().getValue()
: assign(arg.getElement2().value.getResultType(), arg.getElement1().getValue()))
.collect(toList());
return this;
}

Expand Down Expand Up @@ -515,12 +518,15 @@ public MethodGenerator generateAssert() {

SerializedValue[] snapshotSetupArgs = snapshot.getSetupArgs();
AnnotatedValue[] snapshotExpectArgs = snapshot.getAnnotatedExpectArgs();
List<String> expectArgs = IntStream.range(0, snapshotExpectArgs.length)
.filter(i -> !snapshotExpectArgs[i].value.equals(snapshotSetupArgs[i]))
.mapToObj(i -> createAssertion(snapshotExpectArgs[i].value.accept(matcher.create(locals, types), newContext(snapshotExpectArgs[i].annotations)), args.get(i)))
Triple<AnnotatedValue, SerializedValue, String>[] arguments = Triple.zip(snapshotExpectArgs, snapshotSetupArgs, args.toArray(new String[0]));
List<String> expectArgs = Stream.of(arguments)
.filter(arg -> !arg.getElement1().value.equals(arg.getElement2()))
.map(arg -> new Pair<Computation, String>(arg.getElement1().value.accept(matcher.create(locals, types), newContext(arg.getElement1().annotations)), arg.getElement3()))
.filter(arg -> arg.getElement1() != null)
.map(arg -> createAssertion(arg.getElement1(), arg.getElement2()))
.flatMap(statements -> statements.stream())
.collect(toList());

statements.addAll(expectArgs);

SerializedField[] serializedGlobals = snapshot.getExpectGlobals();
Expand All @@ -542,7 +548,6 @@ public MethodGenerator generateAssert() {
}

private List<String> createAssertion(Computation matcher, String exp) {

List<String> statements = new ArrayList<>();

statements.addAll(matcher.getStatements());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.lang.reflect.Type;
import java.util.List;
import java.util.Objects;

import org.hamcrest.Matcher;

Expand All @@ -33,6 +34,7 @@ public Computation tryDeserialize(SerializedObject value, MatcherGenerators gene
List<Computation> fields = value.getFields().stream()
.sorted()
.map(field -> field.accept(generator))
.filter(Objects::nonNull)
.collect(toList());

List<String> fieldComputations = fields.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,146 +27,156 @@
import net.amygdalum.testrecorder.deserializers.DeserializerFactory;
import net.amygdalum.testrecorder.deserializers.LocalVariableNameGenerator;
import net.amygdalum.testrecorder.deserializers.TypeManager;
import net.amygdalum.testrecorder.hints.SkipChecks;
import net.amygdalum.testrecorder.util.GenericMatcher;
import net.amygdalum.testrecorder.values.SerializedField;
import net.amygdalum.testrecorder.values.SerializedLiteral;
import net.amygdalum.testrecorder.values.SerializedNull;

public class MatcherGenerators implements Deserializer<Computation> {

public static final Adaptors<MatcherGenerators> DEFAULT = new Adaptors<MatcherGenerators>()
.load(MatcherGenerator.class);
public static final Adaptors<MatcherGenerators> DEFAULT = new Adaptors<MatcherGenerators>()
.load(MatcherGenerator.class);

private LocalVariableNameGenerator locals;
private TypeManager types;
private Adaptors<MatcherGenerators> adaptors;
private LocalVariableNameGenerator locals;
private TypeManager types;
private Adaptors<MatcherGenerators> adaptors;

private Set<SerializedValue> computed;
private Set<SerializedValue> computed;

public MatcherGenerators(Class<?> clazz) {
this(new LocalVariableNameGenerator(), new TypeManager(clazz.getPackage().getName()), DEFAULT);
}

public MatcherGenerators(Class<?> clazz) {
this(new LocalVariableNameGenerator(), new TypeManager(clazz.getPackage().getName()), DEFAULT);
}
public MatcherGenerators(LocalVariableNameGenerator locals, TypeManager types) {
this(locals, types, DEFAULT);
}

public MatcherGenerators(LocalVariableNameGenerator locals, TypeManager types) {
this(locals, types, DEFAULT);
}
public MatcherGenerators(LocalVariableNameGenerator locals, TypeManager types, Adaptors<MatcherGenerators> adaptors) {
this.locals = locals;
this.types = types;
this.adaptors = adaptors;
this.computed = new HashSet<>();
}

public MatcherGenerators(LocalVariableNameGenerator locals, TypeManager types, Adaptors<MatcherGenerators> adaptors) {
this.locals = locals;
this.types = types;
this.adaptors = adaptors;
this.computed = new HashSet<>();
}

public LocalVariableNameGenerator getLocals() {
public LocalVariableNameGenerator getLocals() {
return locals;
}

public TypeManager getTypes() {
return types;
}
public TypeManager getTypes() {
return types;
}

public boolean isSimpleValue(SerializedValue element) {
return element instanceof SerializedNull
|| element instanceof SerializedLiteral;
public boolean isSimpleValue(SerializedValue element) {
return element instanceof SerializedNull
|| element instanceof SerializedLiteral;
}

public Computation simpleMatcher(SerializedValue element) {
return simpleMatcher(element, DeserializerContext.NULL);
}

public Computation simpleMatcher(SerializedValue element, DeserializerContext context) {
if (element instanceof SerializedNull) {
types.staticImport(Matchers.class, "nullValue");
return new Computation(nullMatcher(""), element.getResultType());
} else if (element instanceof SerializedLiteral) {
return new Computation(asLiteral(((SerializedLiteral) element).getValue()), element.getResultType());
} else {
return element.accept(this, context);
}
}

public Computation simpleMatcher(SerializedValue element, DeserializerContext context) {
if (element instanceof SerializedNull) {
types.staticImport(Matchers.class, "nullValue");
return new Computation(nullMatcher(""), element.getResultType());
} else if (element instanceof SerializedLiteral) {
return new Computation(asLiteral(((SerializedLiteral) element).getValue()), element.getResultType());
} else {
return element.accept(this, context);
}
}

public Computation simpleValue(SerializedValue element) {
return simpleValue(element, DeserializerContext.NULL);
}

public Computation simpleValue(SerializedValue element, DeserializerContext context) {
if (element instanceof SerializedNull) {
return new Computation("null", element.getResultType());
} else if (element instanceof SerializedLiteral) {
return new Computation(asLiteral(((SerializedLiteral) element).getValue()), element.getResultType());
} else {
return element.accept(this, context);
}
}

@Override
public Computation visitField(SerializedField field, DeserializerContext context) {
SerializedValue fieldValue = field.getValue();
DeserializerContext fieldContext = newContext(field.getAnnotations());
if (types.isHidden(field.getType())) {
types.registerImport(Matcher.class);
Computation value = fieldValue.accept(this, fieldContext);

String genericType = types.getRelaxedName(value.getType());

String assignField = assignLocalVariableStatement(genericType, field.getName(), value.getValue());
return new Computation(assignField, null, value.getStatements());
} else if (isSimpleValue(fieldValue)) {
types.registerImport(baseType(field.getType()));
Computation value = simpleValue(fieldValue, fieldContext);

String assignField = assignLocalVariableStatement(types.getRawName(field.getType()), field.getName(), value.getValue());
return new Computation(assignField, null, value.getStatements());
} else {
types.registerImport(Matcher.class);
Computation value = fieldValue.accept(this, fieldContext);

String genericType = types.getRelaxedName(value.getType());

String assignField = assignLocalVariableStatement(genericType, field.getName(), value.getValue());
return new Computation(assignField, null, value.getStatements());
}
}

@Override
public Computation visitReferenceType(SerializedReferenceType value, DeserializerContext context) {
if (!computed.add(value)) {
types.staticImport(GenericMatcher.class, "recursive");
Type resultType = value.getResultType().equals(value.getType()) ? parameterized(Matcher.class, null, value.getResultType()) : parameterized(Matcher.class, null, wildcard());
if (!types.isHidden(value.getType())) {
return new Computation(recursiveMatcher(types.getRawTypeName(value.getType())), resultType);
} else if (!types.isHidden(value.getResultType())) {
return new Computation(recursiveMatcher(types.getRawTypeName(value.getResultType())), resultType);
} else {
return new Computation(recursiveMatcher(types.getRawTypeName(Object.class)), parameterized(Matcher.class, null, wildcard()));
}
}
return adaptors.tryDeserialize(value, types, this, context);
}

@Override
public Computation visitImmutableType(SerializedImmutableType value, DeserializerContext context) {
return adaptors.tryDeserialize(value, types, this, context);
}

@Override
public Computation visitValueType(SerializedValueType value, DeserializerContext context) {
return adaptors.tryDeserialize(value, types, this, context);
}

public static class Factory implements DeserializerFactory {

@Override
public Deserializer<Computation> create(LocalVariableNameGenerator locals, TypeManager types) {
return new MatcherGenerators(locals, types);
}

@Override
public Type resultType(Type type) {
return parameterized(Matcher.class, null, type);
}
}
}

public Computation simpleValue(SerializedValue element, DeserializerContext context) {
if (element instanceof SerializedNull) {
return new Computation("null", element.getResultType());
} else if (element instanceof SerializedLiteral) {
return new Computation(asLiteral(((SerializedLiteral) element).getValue()), element.getResultType());
} else {
return element.accept(this, context);
}
}

@Override
public Computation visitField(SerializedField field, DeserializerContext context) {
SerializedValue fieldValue = field.getValue();
DeserializerContext fieldContext = newContext(field.getAnnotations());
if (fieldContext.getHint(SkipChecks.class).isPresent()) {
return null;
} else if (types.isHidden(field.getType())) {
types.registerImport(Matcher.class);
Computation value = fieldValue.accept(this, fieldContext);

String genericType = types.getRelaxedName(value.getType());

String assignField = assignLocalVariableStatement(genericType, field.getName(), value.getValue());
return new Computation(assignField, null, value.getStatements());
} else if (isSimpleValue(fieldValue)) {
types.registerImport(baseType(field.getType()));
Computation value = simpleValue(fieldValue, fieldContext);

String assignField = assignLocalVariableStatement(types.getRawName(field.getType()), field.getName(), value.getValue());
return new Computation(assignField, null, value.getStatements());
} else {
types.registerImport(Matcher.class);
Computation value = fieldValue.accept(this, fieldContext);

String genericType = types.getRelaxedName(value.getType());

String assignField = assignLocalVariableStatement(genericType, field.getName(), value.getValue());
return new Computation(assignField, null, value.getStatements());
}
}

@Override
public Computation visitReferenceType(SerializedReferenceType value, DeserializerContext context) {
if (context.getHint(SkipChecks.class).isPresent()) {
return null;
} else if (!computed.add(value)) {
types.staticImport(GenericMatcher.class, "recursive");
Type resultType = value.getResultType().equals(value.getType()) ? parameterized(Matcher.class, null, value.getResultType()) : parameterized(Matcher.class, null, wildcard());
if (!types.isHidden(value.getType())) {
return new Computation(recursiveMatcher(types.getRawTypeName(value.getType())), resultType);
} else if (!types.isHidden(value.getResultType())) {
return new Computation(recursiveMatcher(types.getRawTypeName(value.getResultType())), resultType);
} else {
return new Computation(recursiveMatcher(types.getRawTypeName(Object.class)), parameterized(Matcher.class, null, wildcard()));
}
}
return adaptors.tryDeserialize(value, types, this, context);
}

@Override
public Computation visitImmutableType(SerializedImmutableType value, DeserializerContext context) {
if (context.getHint(SkipChecks.class).isPresent()) {
return null;
}
return adaptors.tryDeserialize(value, types, this, context);
}

@Override
public Computation visitValueType(SerializedValueType value, DeserializerContext context) {
if (context.getHint(SkipChecks.class).isPresent()) {
return null;
}
return adaptors.tryDeserialize(value, types, this, context);
}

public static class Factory implements DeserializerFactory {

@Override
public Deserializer<Computation> create(LocalVariableNameGenerator locals, TypeManager types) {
return new MatcherGenerators(locals, types);
}

@Override
public Type resultType(Type type) {
return parameterized(Matcher.class, null, type);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package net.amygdalum.testrecorder.util;

import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.READ;
import static java.nio.file.StandardOpenOption.SYNC;
import static java.nio.file.StandardOpenOption.WRITE;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
Expand All @@ -8,7 +13,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

Expand All @@ -22,7 +26,7 @@ public static String store(String dir, Object object) {
String string = digest(data);
Path path = Paths.get(dir, string + ".serialized");
Files.createDirectories(path.getParent());
try (OutputStream o = Files.newOutputStream(path, StandardOpenOption.SYNC)) {
try (OutputStream o = Files.newOutputStream(path, SYNC, CREATE, WRITE)) {
o.write(data);
o.flush();

Expand Down Expand Up @@ -56,7 +60,7 @@ private static String digest(byte[] data) throws NoSuchAlgorithmException {
}

public static <T> T load(String dir, String fileName, Class<T> type) {
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(Paths.get(dir, fileName)))) {
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(Paths.get(dir, fileName), READ))) {
Object rawObject = in.readObject();
T object = type.cast(rawObject);
return object;
Expand Down
Loading

0 comments on commit c08f7dc

Please sign in to comment.