Skip to content

Commit

Permalink
Merge 021d73c into 1750995
Browse files Browse the repository at this point in the history
  • Loading branch information
boretti committed May 19, 2020
2 parents 1750995 + 021d73c commit cd5228a
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 23 deletions.
Expand Up @@ -36,7 +36,7 @@
import ch.powerunit.extensions.matchers.common.ListJoining;
import ch.powerunit.extensions.matchers.provideprocessor.fields.AbstractFieldDescription;
import ch.powerunit.extensions.matchers.provideprocessor.fields.FieldDescriptionMetaData;
import ch.powerunit.extensions.matchers.provideprocessor.fields.IgoreFieldDescription;
import ch.powerunit.extensions.matchers.provideprocessor.fields.IgnoreFieldDescription;
import ch.powerunit.extensions.matchers.provideprocessor.xml.GeneratedMatcher;

public abstract class ProvidesMatchersAnnotatedElementFieldMatcherMirror
Expand All @@ -58,7 +58,7 @@ private List<AbstractFieldDescription> generateFields(TypeElement typeElement,
.collect(collectingAndThen(
groupingBy(FieldDescriptionMetaData::getFieldName,
reducing(null,
(v1, v2) -> v1 == null ? v2 : v1 instanceof IgoreFieldDescription ? v1 : v2)),
(v1, v2) -> v1 == null ? v2 : v1 instanceof IgnoreFieldDescription ? v1 : v2)),
c -> c == null ? emptyList() : c.values().stream().collect(toList())));
}

Expand Down Expand Up @@ -103,7 +103,7 @@ public String generateMetadata() {
+ " * Metadata regarding this matcher.\n"
+ " */\n"
+ " public static final Metadata METADATA = new Metadata();\n\n"
+" public static final class FieldMetadata {\n public final String NAME, TYPE, ACCESSOR;\n public final boolean IGNORED;\n private FieldMetadata(String name, String type, String accessor, boolean ignored) {\n NAME=name; TYPE=type; ACCESSOR=accessor; IGNORED=ignored;\n }\n }\n\n"
+" public static final class FieldMetadata {\n public final String NAME, TYPE, ACCESSOR, STEREOTYPE;\n public final boolean IGNORED;\n private FieldMetadata(String name, String type, String accessor,String stereotype, boolean ignored) {\n NAME=name; TYPE=type; ACCESSOR=accessor; STEREOTYPE=stereotype; IGNORED=ignored;\n }\n }\n\n"
+ " public static final class Metadata {\n\n"
+ " private Metadata() {}\n\n"
+ " public final String ANNOTATION_PROCESSOR_VERSION = \"" + getAnnotationProcessorVersion() + "\";\n\n"
Expand Down
Expand Up @@ -19,6 +19,7 @@
*/
package ch.powerunit.extensions.matchers.provideprocessor.fields;

import static ch.powerunit.extensions.matchers.common.CommonUtils.toJavaSyntax;
import static java.util.stream.Collectors.joining;

import java.util.Optional;
Expand All @@ -28,7 +29,6 @@
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;

import ch.powerunit.extensions.matchers.common.CommonUtils;
import ch.powerunit.extensions.matchers.provideprocessor.ProvidesMatchersAnnotatedElementData;
import ch.powerunit.extensions.matchers.provideprocessor.ProvidesMatchersAnnotatedElementMirror;
import ch.powerunit.extensions.matchers.provideprocessor.RoundMirror;
Expand Down Expand Up @@ -58,9 +58,7 @@ public FieldDescriptionMetaData(ProvidesMatchersAnnotatedElementData containingE
super(containingElementMirror);
this.mirror = mirror;
RoundMirror roundMirror = containingElementMirror.getRoundMirror();
TypeMirror fieldTypeMirror = (mirror.getFieldElement() instanceof ExecutableElement)
? ((ExecutableElement) mirror.getFieldElement()).getReturnType()
: mirror.getFieldElement().asType();
TypeMirror fieldTypeMirror = mirror.getFieldTypeMirror();
this.defaultReturnMethod = containingElementMirror.getDefaultReturnMethod();
this.generic = computeGenericInformation(fieldTypeMirror);
this.fullyQualifiedNameMatcherInSameRound = mirror.computeFullyQualifiedNameMatcherInSameRound(roundMirror);
Expand Down Expand Up @@ -94,9 +92,7 @@ public String getFieldCopySameRound(String lhs, String rhs) {
public String getFieldCopy(String lhs, String rhs) {
if (fullyQualifiedNameMatcherInSameRound != null
&& mirror.getFieldTypeAsTypeElement().getTypeParameters().isEmpty()
&& Optional
.ofNullable(containingElementMirror.getRoundMirror()
.getByName(getFieldType()))
&& Optional.ofNullable(containingElementMirror.getRoundMirror().getByName(getFieldType()))
.map(ProvidesMatchersAnnotatedElementMirror::hasWithSameValue).orElse(false)) {
return getFieldCopySameRound(lhs, rhs);
}
Expand Down Expand Up @@ -160,9 +156,9 @@ public GeneratedMatcherField asGeneratedMatcherField() {
}

public String generateMetadata(String className) {
return "new " + className + "(" + CommonUtils.toJavaSyntax(getFieldName()) + ","
+ CommonUtils.toJavaSyntax(getFieldType()) + "," + CommonUtils.toJavaSyntax(getFieldAccessor()) + ","
+ Boolean.toString(this instanceof IgoreFieldDescription) + ")";
return "new " + className + "(" + toJavaSyntax(getFieldName()) + "," + toJavaSyntax(getFieldType()) + ","
+ toJavaSyntax(getFieldAccessor()) + "," + toJavaSyntax(getClass().getSimpleName()) + ","
+ Boolean.toString(this instanceof IgnoreFieldDescription) + ")";
}

}
Expand Up @@ -69,12 +69,16 @@ public Element getFieldElement() {
public TypeElement getFieldTypeAsTypeElement() {
return fieldTypeAsTypeElement;
}

public TypeMirror getFieldTypeMirror() {
return (fieldElement instanceof ExecutableElement)
? ((ExecutableElement) fieldElement).getReturnType()
: fieldElement.asType();
}

public String computeFullyQualifiedNameMatcherInSameRound(RoundMirror roundMirror) {
ProcessingEnvironment processingEnv = roundMirror.getProcessingEnv();
TypeMirror fieldTypeMirror = (fieldElement instanceof ExecutableElement)
? ((ExecutableElement) fieldElement).getReturnType()
: fieldElement.asType();
TypeMirror fieldTypeMirror = getFieldTypeMirror();
if (roundMirror.isInSameRound(processingEnv.getTypeUtils().asElement(fieldTypeMirror))
&& fieldTypeAsTypeElement != null) {
return new ProvideMatchersMirror(roundMirror, fieldTypeAsTypeElement)
Expand Down
Expand Up @@ -42,7 +42,7 @@ private FieldDescriptionProvider() {
}

public static enum Type {
NA, ARRAY, COLLECTION, LIST, SET, OPTIONAL, COMPARABLE, STRING, SUPPLIER, PRIMITIVE
NA, MAP, ARRAY, COLLECTION, LIST, SET, OPTIONAL, COMPARABLE, STRING, SUPPLIER, PRIMITIVE
}

public static final class ExtracTypeVisitor extends AbstractTypeKindVisitor<Type, Void, RoundMirror> {
Expand Down Expand Up @@ -77,6 +77,8 @@ public Type visitArray(ArrayType t, Void ignore) {
public Type visitDeclared(DeclaredType t, Void ignore) {
if (isAssignable(t, "java.util.Optional")) {
return Type.OPTIONAL;
} else if (isAssignable(t, "java.util.Map")) {
return Type.MAP;
} else if (isAssignable(t, "java.util.Set")) {
return Type.SET;
} else if (isAssignable(t, "java.util.List")) {
Expand Down Expand Up @@ -105,18 +107,29 @@ public Type visitUnknown(TypeMirror t, Void ignore) {
}
}

public static AbstractFieldDescription of(ProvidesMatchersAnnotatedElementData containingElementMirror,
public static boolean isIgnored(FieldDescriptionMirror mirror) {
return mirror.getFieldElement().getAnnotation(IgnoreInMatcher.class) != null;
}

public static Type getTypeMirror(ProvidesMatchersAnnotatedElementData containingElementMirror,
FieldDescriptionMirror mirror) {
Element te = mirror.getFieldElement();
Type type = new ExtracTypeVisitor(containingElementMirror.getRoundMirror()).visit(
return new ExtracTypeVisitor(containingElementMirror.getRoundMirror()).visit(
(te instanceof ExecutableElement) ? ((ExecutableElement) te).getReturnType() : te.asType(), null);
if (te.getAnnotation(IgnoreInMatcher.class) != null) {
return new IgoreFieldDescription(containingElementMirror, mirror);
}

public static AbstractFieldDescription of(ProvidesMatchersAnnotatedElementData containingElementMirror,
FieldDescriptionMirror mirror) {
Type type = getTypeMirror(containingElementMirror, mirror);
if (isIgnored(mirror)) {
return new IgnoreFieldDescription(containingElementMirror, mirror);
}

switch (type) {
case ARRAY:
return new ArrayFieldDescription(containingElementMirror, mirror);
case MAP:
return new MapFieldDescription(containingElementMirror, mirror);
case COLLECTION:
case SET:
case LIST:
Expand Down
Expand Up @@ -28,9 +28,9 @@
import ch.powerunit.extensions.matchers.provideprocessor.ProvidesMatchersAnnotatedElementData;
import ch.powerunit.extensions.matchers.provideprocessor.xml.GeneratedMatcherField;

public final class IgoreFieldDescription extends AbstractFieldDescription {
public final class IgnoreFieldDescription extends AbstractFieldDescription {

public IgoreFieldDescription(ProvidesMatchersAnnotatedElementData containingElementMirror,
public IgnoreFieldDescription(ProvidesMatchersAnnotatedElementData containingElementMirror,
FieldDescriptionMirror mirror) {
super(containingElementMirror, mirror);
}
Expand Down
@@ -0,0 +1,88 @@
/**
*
*/
package ch.powerunit.extensions.matchers.provideprocessor.fields;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Optional;

import javax.lang.model.type.DeclaredType;

import ch.powerunit.extensions.matchers.provideprocessor.ProvidesMatchersAnnotatedElementData;
import ch.powerunit.extensions.matchers.provideprocessor.ProvidesMatchersAnnotatedElementMirror;

public class MapFieldDescription extends DefaultFieldDescription {

private static final String EMPTY_MATCHER = "new org.hamcrest.CustomTypeSafeMatcher<%1$s>(\"map is empty\"){ public boolean matchesSafely(%1$s o) {return o.isEmpty();}}";

private static final String SIZE_MATCHER = "new org.hamcrest.CustomTypeSafeMatcher<%1$s>(\"map size is \"+other.size()){ public boolean matchesSafely(%1$s o) {return o.size()==other.size();} protected void describeMismatchSafely(%1$s item, org.hamcrest.Description mismatchDescription) {mismatchDescription.appendText(\" was size=\").appendValue(item.size());}}";

public MapFieldDescription(ProvidesMatchersAnnotatedElementData containingElementMirror,
FieldDescriptionMirror mirror) {
super(containingElementMirror, mirror);
}

@Override
protected Collection<FieldDSLMethod> getSpecificFieldDslMethodFor() {
String fieldType = getFieldType();
final String emptyMatcher = String.format(EMPTY_MATCHER, fieldType);

Collection<FieldDSLMethod> tmp = new ArrayList<>();
tmp.add(getDslMethodBuilder().withSuffixDeclarationJavadocAndDefault("IsEmpty", "the map is empty",
emptyMatcher));
if (!"".equals(generic)) {
Object matchers[] = Optional.of(mirror.getFieldTypeMirror()).filter(m -> m instanceof DeclaredType)
.map(DeclaredType.class::cast).filter(m -> m.getTypeArguments().size() == 2)
.map(m -> m.getTypeArguments().stream().map(Object::toString)
.map(o -> Optional.ofNullable(getByName(o))
.filter(ProvidesMatchersAnnotatedElementMirror::hasWithSameValue)
.map(t -> t.getFullyQualifiedNameOfGeneratedClass() + "."
+ t.getMethodShortClassName() + "WithSameValue")
.orElse(MATCHERS + ".is"))
.toArray())
.orElse(new String[] { MATCHERS + ".is", MATCHERS + ".is" });

tmp.add(generateHasSameValue(fieldType, matchers[0].toString(), matchers[1].toString()));
}
return tmp;
}

private FieldDSLMethod generateHasSameValue(String fieldType, String keyMatcher, String keyValue) {
final String sizeMatcher = String.format(SIZE_MATCHER, fieldType);
return getDslMethodBuilder().withDeclaration("HasSameValues", fieldType + " other")
.withJavaDoc("verify that the value from the other map are exactly the once inside this map",
"other the other map")
.havingDefault(MATCHERS + ".both(" + sizeMatcher + ").and(" + MATCHERS
+ ".allOf(other.entrySet().stream().map(kv->" + MATCHERS + ".hasEntry(" + keyMatcher
+ "(kv.getKey())," + keyValue
+ "(kv.getValue()))).collect(java.util.stream.Collectors.toList())))");
}

@Override
public String getMatcherForField() {
String matcher = super.getMatcherForField();
if (!"".equals(generic)) {
String localGeneric = generic.contains("?") ? "" : "<" + generic + ">";
matcher += "\n" + String.format(
"private static class %1$sMatcherSameValue%2$s extends org.hamcrest.FeatureMatcher<%3$s,%4$s> {\n public %1$sMatcherSameValue(org.hamcrest.Matcher<? super %4$s> matcher) {\n super(matcher,\"%5$s\",\"%5$s\");\n }\n protected %4$s featureValueOf(%3$s actual) {\n return (java.util.Set)actual.entrySet();\n }\n}\n",
mirror.getMethodFieldName(), containingElementMirror.getFullGeneric(), getFieldType(),
"java.util.Set<java.util.Map.Entry" + localGeneric + ">", " [entries of] ");
}
return matcher;
}

@Override
public String getFieldCopy(String lhs, String rhs) {
if (!"".equals(generic)) {
String fieldAccessor = getFieldAccessor();
String fieldName = getFieldName();
return "if(" + rhs + "." + fieldAccessor + "==null) {" + lhs + "." + fieldName + "(" + MATCHERS
+ ".nullValue()); } else {" + lhs + "." + fieldName + "HasSameValues(" + rhs + "." + fieldAccessor
+ ");}";
}
return super.getFieldCopy(lhs, rhs);

}

}
@@ -0,0 +1,22 @@
package ch.powerunit.extensions.matchers.samples;

import java.util.Map;

import ch.powerunit.extensions.matchers.ProvideMatchers;
import ch.powerunit.extensions.matchers.samples.extension.MyTestWithoutGeneric;
import ch.powerunit.extensions.matchers.samples.extension.MyTestWithoutGeneric2;

@ProvideMatchers
public class MapSample<E, V> {
public Map<String, Integer> map1;

public Map<E, V> map2;

public Map map3;

public Map<?, ?> map4;

public Map<String, MyTestWithoutGeneric> map5;

public Map<String, MyTestWithoutGeneric2> map6;
}
@@ -0,0 +1,24 @@
package ch.powerunit.extensions.matchers.samples;

import java.util.Collections;

import ch.powerunit.Test;
import ch.powerunit.TestSuite;
import ch.powerunit.extensions.matchers.samples.extension.MyTestWithoutGeneric2;

public class MapSampleTest implements TestSuite {
@Test
public void testSameValue() {
MapSample<String, Long> ms = new MapSample<>();
ms.map1 = Collections.singletonMap("x", 12);
ms.map2 = Collections.singletonMap("y", 12L);
ms.map3 = Collections.singletonMap("z", "a");
ms.map4 = Collections.singletonMap("a", "b");
assertThat(ms).is(MapSampleMatchers.<String, Long>mapSampleWith()
.map1HasSameValues(Collections.singletonMap("x", 12)).build());
assertThat(ms).isNot(
MapSampleMatchers.<String, Long>mapSampleWith().map1HasSameValues(Collections.emptyMap()).build());
assertThat(ms).isNot(MapSampleMatchers.<String, Long>mapSampleWith()
.map6HasSameValues(Collections.singletonMap("x", new MyTestWithoutGeneric2("z"))).build());
}
}

0 comments on commit cd5228a

Please sign in to comment.