#36 Allowing messages to be used in diagnostic expectations

This commit is contained in:
Gunnar Morling 2013-06-09 21:16:24 +02:00
parent e53adbd817
commit 60126183a3
6 changed files with 125 additions and 16 deletions

View File

@ -364,11 +364,11 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
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() ) {

View File

@ -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.
* </p>
* 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<DiagnosticDescriptor> actualDiagnostics,
List<DiagnosticDescriptor> expectedDiagnostics) {
Collections.sort( actualDiagnostics, COMPARATOR );
Collections.sort( expectedDiagnostics, COMPARATOR );
Iterator<DiagnosticDescriptor> actualIterator = actualDiagnostics.iterator();
Iterator<DiagnosticDescriptor> 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<DiagnosticDescriptor> {
@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() );
}
}
}

View File

@ -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 ".*";
}

View File

@ -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 { };
}

View File

@ -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<DiagnosticDescriptor> diagnostics;
private List<DiagnosticDescriptor> diagnostics;
private CompilationOutcomeDescriptor(CompilationResult compilationResult,
Set<DiagnosticDescriptor> diagnostics) {
List<DiagnosticDescriptor> diagnostics) {
this.compilationResult = compilationResult;
this.diagnostics = diagnostics;
}
@ -50,11 +49,11 @@ public class CompilationOutcomeDescriptor {
if ( expectedCompilationResult == null ) {
return new CompilationOutcomeDescriptor(
CompilationResult.SUCCEEDED,
Collections.<DiagnosticDescriptor>emptySet()
Collections.<DiagnosticDescriptor>emptyList()
);
}
else {
Set<DiagnosticDescriptor> diagnosticDescriptors = new HashSet<DiagnosticDescriptor>();
List<DiagnosticDescriptor> diagnosticDescriptors = new ArrayList<DiagnosticDescriptor>();
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<DiagnosticDescriptor> diagnosticDescriptors = new HashSet<DiagnosticDescriptor>();
List<DiagnosticDescriptor> diagnosticDescriptors = new ArrayList<DiagnosticDescriptor>();
for ( Diagnostic<? extends JavaFileObject> diagnostic : diagnostics ) {
//ignore notes created by the compiler
if ( diagnostic.getKind() != Kind.NOTE ) {
@ -84,7 +83,7 @@ public class CompilationOutcomeDescriptor {
return compilationResult;
}
public Set<DiagnosticDescriptor> getDiagnostics() {
public List<DiagnosticDescriptor> getDiagnostics() {
return diagnostics;
}

View File

@ -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 )
);
}