From 60126183a32573ae437efc8f1f17d1dd9b319ff7 Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Sun, 9 Jun 2013 21:16:24 +0200 Subject: [PATCH] #36 Allowing messages to be used in diagnostic expectations --- .../mapstruct/ap/MapperGenerationVisitor.java | 4 +- .../mapstruct/ap/testutil/MapperTestBase.java | 78 ++++++++++++++++++- .../compilation/annotation/Diagnostic.java | 22 ++++++ .../ExpectedCompilationOutcome.java | 13 +++- .../model/CompilationOutcomeDescriptor.java | 15 ++-- .../model/DiagnosticDescriptor.java | 9 ++- 6 files changed, 125 insertions(+), 16 deletions(-) diff --git a/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java b/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java index ef7ad7265..a6f7ada9c 100644 --- a/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java +++ b/processor/src/main/java/org/mapstruct/ap/MapperGenerationVisitor.java @@ -364,11 +364,11 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { if ( declaringMapper == null ) { if ( parameter.getType().isIterableType() && !returnType.isIterableType() ) { - reportError( "Can't generate mapping method from iterable type to non-iterable ype.", method ); + reportError( "Can't generate mapping method from iterable type to non-iterable type.", method ); mappingErroneous = true; } if ( !parameter.getType().isIterableType() && returnType.isIterableType() ) { - reportError( "Can't generate mapping method from non-iterable type to iterable ype.", method ); + reportError( "Can't generate mapping method from non-iterable type to iterable type.", method ); mappingErroneous = true; } if ( parameter.getType().isPrimitive() ) { diff --git a/processor/src/test/java/org/mapstruct/ap/testutil/MapperTestBase.java b/processor/src/test/java/org/mapstruct/ap/testutil/MapperTestBase.java index 1f6257e50..388aa32ab 100644 --- a/processor/src/test/java/org/mapstruct/ap/testutil/MapperTestBase.java +++ b/processor/src/test/java/org/mapstruct/ap/testutil/MapperTestBase.java @@ -26,6 +26,8 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; import java.util.List; import javax.tools.DiagnosticCollector; import javax.tools.JavaCompiler; @@ -39,19 +41,26 @@ import org.mapstruct.ap.MappingProcessor; import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult; import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome; import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor; +import org.mapstruct.ap.testutil.compilation.model.DiagnosticDescriptor; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import static org.fest.assertions.Assertions.assertThat; /** - * Base class for all mapper tests. The classes to be compiled for a given test - * method must be specified via {@link WithClasses}. + * Base class for all mapper tests. + *

+ * The classes to be compiled for a given test method must be specified via + * {@link WithClasses}. Optionally the expected compilation outcome and expected + * diagnostics can be specified via {@link ExpectedCompilationOutcome}. If no + * outcome is specified, a successful compilation is assumed. * * @author Gunnar Morling */ public abstract class MapperTestBase { + private static final DiagnosticDescriptorComparator COMPARATOR = new DiagnosticDescriptorComparator(); + private JavaCompiler compiler; private String sourceDir; private String classOutputDir; @@ -118,7 +127,50 @@ public abstract class MapperTestBase { .isEqualTo( CompilationResult.FAILED ); } - assertThat( actualResult.getDiagnostics() ).isEqualTo( expectedResult.getDiagnostics() ); + assertDiagnostics( actualResult.getDiagnostics(), expectedResult.getDiagnostics() ); + } + + private void assertDiagnostics(List actualDiagnostics, + List expectedDiagnostics) { + + Collections.sort( actualDiagnostics, COMPARATOR ); + Collections.sort( expectedDiagnostics, COMPARATOR ); + + Iterator actualIterator = actualDiagnostics.iterator(); + Iterator expectedIterator = expectedDiagnostics.iterator(); + + while ( actualIterator.hasNext() ) { + assertThat( expectedIterator.hasNext() ).describedAs( + String.format( + "Found less diagnostics than expected. Actual: %s; Expected: %s.", + actualDiagnostics, + expectedDiagnostics + ) + ).isTrue(); + + DiagnosticDescriptor actual = actualIterator.next(); + DiagnosticDescriptor expected = expectedIterator.next(); + + assertThat( actual.getSourceFileName() ).isEqualTo( expected.getSourceFileName() ); + assertThat( actual.getLine() ).isEqualTo( expected.getLine() ); + assertThat( actual.getKind() ).isEqualTo( expected.getKind() ); + assertThat( actual.getMessage() ).describedAs( + String.format( + "%s:%s %s", + actual.getSourceFileName(), + actual.getLine(), + actual.getKind() + ) + ).matches( expected.getMessage() ); + } + + assertThat( expectedIterator.hasNext() ).describedAs( + String.format( + "Found more diagnostics than expected. Actual: %s; Expected: %s.", + actualDiagnostics, + expectedDiagnostics + ) + ).isFalse(); } /** @@ -221,4 +273,24 @@ public abstract class MapperTestBase { } path.delete(); } + + private static class DiagnosticDescriptorComparator implements Comparator { + + @Override + public int compare(DiagnosticDescriptor o1, DiagnosticDescriptor o2) { + int result = o1.getSourceFileName().compareTo( o2.getSourceFileName() ); + + if ( result != 0 ) { + return result; + } + result = Long.valueOf( o1.getLine() ).compareTo( o2.getLine() ); + if ( result != 0 ) { + return result; + } + + // Using the message is not perfect when using regular expressions, + // but it's better than nothing + return o1.getMessage().compareTo( o2.getMessage() ); + } + } } diff --git a/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/Diagnostic.java b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/Diagnostic.java index 4a3a38a1c..22702130b 100644 --- a/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/Diagnostic.java +++ b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/Diagnostic.java @@ -27,9 +27,31 @@ import javax.tools.Diagnostic.Kind; */ public @interface Diagnostic { + /** + * The type for which the diagnostic was created. + * + * @return The type for which the diagnostic was created. + */ Class type(); + /** + * The expected kind of diagnostic. + * + * @return The expected kind of diagnostic. + */ Kind kind(); + /** + * The expected line number of the diagnostic. + * + * @return The expected line number of the diagnostic. + */ int line(); + + /** + * A regular expression matching the expected message of the diagnostic. + * + * @return A regular expression matching the expected message of the diagnostic. + */ + String messageRegExp() default ".*"; } diff --git a/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/ExpectedCompilationOutcome.java b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/ExpectedCompilationOutcome.java index 24e23e3cc..b10069d8c 100644 --- a/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/ExpectedCompilationOutcome.java +++ b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/ExpectedCompilationOutcome.java @@ -29,7 +29,18 @@ import java.lang.annotation.RetentionPolicy; */ @Retention(RetentionPolicy.RUNTIME) public @interface ExpectedCompilationOutcome { + + /** + * The expected result of a compilation. + * + * @return The expected result of a compilation. + */ CompilationResult value(); - Diagnostic[] diagnostics(); + /** + * The expected diagnostics created during a compilation. + * + * @return The expected diagnostics created during a compilation. + */ + Diagnostic[] diagnostics() default { }; } diff --git a/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/CompilationOutcomeDescriptor.java b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/CompilationOutcomeDescriptor.java index 75e88e5b2..b5b99da91 100644 --- a/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/CompilationOutcomeDescriptor.java +++ b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/CompilationOutcomeDescriptor.java @@ -18,10 +18,9 @@ */ package org.mapstruct.ap.testutil.compilation.model; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import javax.tools.Diagnostic; import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileObject; @@ -37,10 +36,10 @@ import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutco public class CompilationOutcomeDescriptor { private CompilationResult compilationResult; - private Set diagnostics; + private List diagnostics; private CompilationOutcomeDescriptor(CompilationResult compilationResult, - Set diagnostics) { + List diagnostics) { this.compilationResult = compilationResult; this.diagnostics = diagnostics; } @@ -50,11 +49,11 @@ public class CompilationOutcomeDescriptor { if ( expectedCompilationResult == null ) { return new CompilationOutcomeDescriptor( CompilationResult.SUCCEEDED, - Collections.emptySet() + Collections.emptyList() ); } else { - Set diagnosticDescriptors = new HashSet(); + List diagnosticDescriptors = new ArrayList(); for ( org.mapstruct.ap.testutil.compilation.annotation.Diagnostic diagnostic : expectedCompilationResult.diagnostics() ) { diagnosticDescriptors.add( DiagnosticDescriptor.forDiagnostic( diagnostic ) ); @@ -69,7 +68,7 @@ public class CompilationOutcomeDescriptor { CompilationResult compilationResult = compilationSuccessful ? CompilationResult.SUCCEEDED : CompilationResult.FAILED; - Set diagnosticDescriptors = new HashSet(); + List diagnosticDescriptors = new ArrayList(); for ( Diagnostic diagnostic : diagnostics ) { //ignore notes created by the compiler if ( diagnostic.getKind() != Kind.NOTE ) { @@ -84,7 +83,7 @@ public class CompilationOutcomeDescriptor { return compilationResult; } - public Set getDiagnostics() { + public List getDiagnostics() { return diagnostics; } diff --git a/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/DiagnosticDescriptor.java b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/DiagnosticDescriptor.java index 2a319f263..f508a766d 100644 --- a/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/DiagnosticDescriptor.java +++ b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/DiagnosticDescriptor.java @@ -46,7 +46,12 @@ public class DiagnosticDescriptor { public static DiagnosticDescriptor forDiagnostic(Diagnostic diagnostic) { String soureFileName = diagnostic.type().getName().replace( ".", File.separator ) + ".java"; - return new DiagnosticDescriptor( soureFileName, diagnostic.kind(), diagnostic.line(), "" ); + return new DiagnosticDescriptor( + soureFileName, + diagnostic.kind(), + diagnostic.line(), + diagnostic.messageRegExp() + ); } public static DiagnosticDescriptor forDiagnostic(String sourceDir, @@ -55,7 +60,7 @@ public class DiagnosticDescriptor { getSourceName( sourceDir, diagnostic ), diagnostic.getKind(), diagnostic.getLineNumber(), - "" + diagnostic.getMessage( null ) ); }