From e4763fe862789d5b04fd2d7980d967c08d451171 Mon Sep 17 00:00:00 2001 From: h908714124 Date: Wed, 28 Aug 2019 20:45:09 +0200 Subject: [PATCH] add tests --- .../jbock/coerce/CollectorClassValidator.java | 8 +-- .../jbock/coerce/MapperClassValidator.java | 8 +-- .../main/java/net/jbock/coerce/Resolver.java | 18 +++++- .../java/net/jbock/compiler/TypeTool.java | 2 +- .../java/net/jbock/coerce/ResolverTest.java | 62 +++++++++++++++++++ .../java/net/jbock/compiler/MapperTest.java | 46 ++++++++++++++ 6 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 core/src/test/java/net/jbock/coerce/ResolverTest.java diff --git a/core/src/main/java/net/jbock/coerce/CollectorClassValidator.java b/core/src/main/java/net/jbock/coerce/CollectorClassValidator.java index fe9048b8e..6d6e378b1 100644 --- a/core/src/main/java/net/jbock/coerce/CollectorClassValidator.java +++ b/core/src/main/java/net/jbock/coerce/CollectorClassValidator.java @@ -41,10 +41,10 @@ CollectorInfo getCollectorInfo(TypeElement collectorClass) { } private CollectorType getCollectorType(TypeElement collectorClass) { - Optional supplier = Resolver.resolve( + Optional supplier = Resolver.typecheck( Supplier.class, collectorClass.asType(), - basicInfo.tool()).resolveTypevars(); + basicInfo.tool()); if (supplier.isPresent()) { List typeArgs = asDeclared(supplier.get()).getTypeArguments(); if (typeArgs.isEmpty()) { @@ -52,10 +52,10 @@ private CollectorType getCollectorType(TypeElement collectorClass) { } return CollectorType.create(basicInfo, typeArgs.get(0), true, collectorClass); } - TypeMirror collector = Resolver.resolve( + TypeMirror collector = Resolver.typecheck( Collector.class, collectorClass.asType(), - basicInfo.tool()).resolveTypevars().orElseThrow(() -> + basicInfo.tool()).orElseThrow(() -> boom("not a Collector or Supplier")); return CollectorType.create(basicInfo, collector, false, collectorClass); } diff --git a/core/src/main/java/net/jbock/coerce/MapperClassValidator.java b/core/src/main/java/net/jbock/coerce/MapperClassValidator.java index 0cb23be84..2616877bb 100644 --- a/core/src/main/java/net/jbock/coerce/MapperClassValidator.java +++ b/core/src/main/java/net/jbock/coerce/MapperClassValidator.java @@ -68,10 +68,10 @@ private void checkBound(TypeElement mapperClass) { } private MapperType getMapperType(TypeElement mapperClass) { - Optional supplier = Resolver.resolve( + Optional supplier = Resolver.typecheck( Supplier.class, mapperClass.asType(), - basicInfo.tool()).resolveTypevars(); + basicInfo.tool()); if (supplier.isPresent()) { List typeArgs = asDeclared(supplier.get()).getTypeArguments(); if (typeArgs.isEmpty()) { @@ -79,10 +79,10 @@ private MapperType getMapperType(TypeElement mapperClass) { } return MapperType.create(basicInfo, typeArgs.get(0), true, mapperClass); } - TypeMirror mapper = Resolver.resolve( + TypeMirror mapper = Resolver.typecheck( Function.class, mapperClass.asType(), - basicInfo.tool()).resolveTypevars().orElseThrow(() -> + basicInfo.tool()).orElseThrow(() -> boom("not a Function or Supplier")); return MapperType.create(basicInfo, mapper, false, mapperClass); } diff --git a/core/src/main/java/net/jbock/coerce/Resolver.java b/core/src/main/java/net/jbock/coerce/Resolver.java index ba8a8be97..fd2e27649 100644 --- a/core/src/main/java/net/jbock/coerce/Resolver.java +++ b/core/src/main/java/net/jbock/coerce/Resolver.java @@ -30,7 +30,19 @@ private Resolver( this.tool = tool; } - static Resolver resolve( + /** + * Check if {@code start} is a {@code goal}. + * + * @param goal a type + * @param start a type + * @param tool a tool + * + * @return the {@code goal} type, with typevars resolved + * as far as it can be inferred from {@code start}, + * or {@link Optional#empty() empty} if {@code start} + * is not a {@code goal}. + */ + static Optional typecheck( Class goal, TypeMirror start, TypeTool tool) { @@ -42,7 +54,7 @@ static Resolver resolve( extensions.add(extension); nextGoal = tool.erasure(extension.baseClass().asType()); } - return new Resolver(extensions, tool); + return new Resolver(extensions, tool).resolveTypevars(); } private static Extension findExtension(List family, TypeMirror goal, TypeTool tool) { @@ -68,7 +80,7 @@ private static Extension findExtension(TypeElement typeElement, TypeMirror goal, return null; } - Optional resolveTypevars() { + private Optional resolveTypevars() { if (extensions.isEmpty()) { return Optional.empty(); } diff --git a/core/src/main/java/net/jbock/compiler/TypeTool.java b/core/src/main/java/net/jbock/compiler/TypeTool.java index e0e0dd8ec..2560bda52 100644 --- a/core/src/main/java/net/jbock/compiler/TypeTool.java +++ b/core/src/main/java/net/jbock/compiler/TypeTool.java @@ -272,7 +272,7 @@ public TypeElement getTypeElement(Class clazz) { return elements.getTypeElement(clazz.getCanonicalName()); } - TypeElement asTypeElement(TypeMirror mirror) { + public TypeElement asTypeElement(TypeMirror mirror) { Element element = types.asElement(mirror); if (element == null) { throw new IllegalArgumentException("no element: " + mirror); diff --git a/core/src/test/java/net/jbock/coerce/ResolverTest.java b/core/src/test/java/net/jbock/coerce/ResolverTest.java new file mode 100644 index 000000000..5dfc2f445 --- /dev/null +++ b/core/src/test/java/net/jbock/coerce/ResolverTest.java @@ -0,0 +1,62 @@ +package net.jbock.coerce; + +import net.jbock.compiler.EvaluatingProcessor; +import net.jbock.compiler.TypeTool; +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import java.util.Optional; +import java.util.function.Supplier; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ResolverTest { + + @Test + void resolves() { + + EvaluatingProcessor.source( + "package test;", + "", + "import java.util.function.Supplier;", + "", + "interface StringSupplier extends Supplier { }", + "", + "abstract class Foo implements StringSupplier { }" + ).run("Mapper", (elements, types) -> { + TypeTool tool = new TypeTool(elements, types); + TypeElement mapper = elements.getTypeElement("test.Foo"); + Optional result = Resolver.typecheck(Supplier.class, mapper.asType(), tool); + assertTrue(result.isPresent()); + TypeMirror typeMirror = result.get(); + DeclaredType declared = TypeTool.asDeclared(typeMirror); + assertEquals(1, declared.getTypeArguments().size()); + TypeMirror typeParameter = declared.getTypeArguments().get(0); + TypeElement string = elements.getTypeElement("java.lang.String"); + assertTrue(types.isSameType(string.asType(), typeParameter)); + }); + } + + @Test + void doesNotResolve() { + + EvaluatingProcessor.source( + "package test;", + "", + "import java.util.function.Supplier;", + "", + "interface StringSupplier extends Supplier { }", + "", + "abstract class Foo implements StringSupplier { }" + ).run("Mapper", (elements, types) -> { + TypeTool tool = new TypeTool(elements, types); + TypeElement mapper = elements.getTypeElement("test.Foo"); + Optional result = Resolver.typecheck(String.class, mapper.asType(), tool); + assertFalse(result.isPresent()); + }); + } +} \ No newline at end of file diff --git a/core/src/test/java/net/jbock/compiler/MapperTest.java b/core/src/test/java/net/jbock/compiler/MapperTest.java index e41503150..6bae16ec5 100644 --- a/core/src/test/java/net/jbock/compiler/MapperTest.java +++ b/core/src/test/java/net/jbock/compiler/MapperTest.java @@ -126,6 +126,52 @@ void validMapperTypeParameterWithBounds() { .compilesWithoutError(); } + @Test + void validMapperTypeParameterSupplierWithBounds() { + List sourceLines = withImports( + "@CommandLineArguments", + "abstract class ValidArguments {", + "", + " @Parameter(shortName = 'x',", + " mappedBy = IdentityMapper.class)", + " abstract String string();", + "", + " static class IdentityMapper implements Supplier> {", + " public Function get() {", + " return null;", + " }", + " }", + "}"); + JavaFileObject javaFile = forSourceLines("test.ValidArguments", sourceLines); + assertAbout(javaSources()).that(singletonList(javaFile)) + .processedWith(new Processor()) + .compilesWithoutError(); + } + + @Test + void invalidMapperTypeParameterSupplierWithBounds() { + List sourceLines = withImports( + "@CommandLineArguments", + "abstract class InvalidArguments {", + "", + " @Parameter(shortName = 'x',", + " mappedBy = IdentityMapper.class)", + " abstract String string();", + "", + " static class IdentityMapper implements Supplier> {", + " public Function get() {", + " return null;", + " }", + " }", + "}"); + JavaFileObject javaFile = forSourceLines("test.InvalidArguments", sourceLines); + assertAbout(javaSources()).that(singletonList(javaFile)) + .processedWith(new Processor()) + .failsToCompile() + .withErrorContaining("There is a problem with the mapper class: Invalid bounds on the type parameters of the mapper class."); + } + + @Test void invalidFlagMapper() { List sourceLines = withImports(