From eec600c3bfa58b3b7df59a1b061f24dde11eb414 Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Sun, 12 May 2013 22:02:05 +0200 Subject: [PATCH] Providing infrastructure for tests expecting AP compilation failures --- .../mapstruct/ap/testutil/MapperTestBase.java | 33 ++++- .../annotation/CompilationResult.java | 25 ++++ .../compilation/annotation/Diagnostic.java | 32 +++++ .../ExpectedCompilationOutcome.java | 32 +++++ .../model/CompilationOutcomeDescriptor.java | 124 +++++++++++++++++ .../model/DiagnosticDescriptor.java | 128 ++++++++++++++++++ 6 files changed, 369 insertions(+), 5 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/CompilationResult.java create mode 100644 processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/Diagnostic.java create mode 100644 processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/ExpectedCompilationOutcome.java create mode 100644 processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/CompilationOutcomeDescriptor.java create mode 100644 processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/DiagnosticDescriptor.java 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 6dbc7e6b4..c15e9726a 100644 --- a/processor/src/test/java/org/mapstruct/ap/testutil/MapperTestBase.java +++ b/processor/src/test/java/org/mapstruct/ap/testutil/MapperTestBase.java @@ -17,6 +17,7 @@ package org.mapstruct.ap.testutil; import java.io.File; import java.io.IOException; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -32,6 +33,9 @@ import javax.tools.StandardLocation; import javax.tools.ToolProvider; 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.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; @@ -71,8 +75,8 @@ public abstract class MapperTestBase { String testDependenciesDir = basePath + "/target/test-dependencies/"; classPath = new ArrayList(); - for ( String oneLibrary : libraries ) { - classPath.add( new File( testDependenciesDir, oneLibrary ) ); + for ( String library : libraries ) { + classPath.add( new File( testDependenciesDir, library ) ); } createOutputDirs(); @@ -86,14 +90,33 @@ public abstract class MapperTestBase { } @BeforeMethod - public void generateMapperImplementation() { + public void generateMapperImplementation(Method testMethod) { diagnostics = new DiagnosticCollector(); List sourceFiles = getSourceFiles( getTestClasses() ); boolean compilationSuccessful = compile( diagnostics, sourceFiles ); - assertThat( compilationSuccessful ).describedAs( "Compilation failed: " + diagnostics.getDiagnostics() ) - .isTrue(); + CompilationOutcomeDescriptor actualResult = CompilationOutcomeDescriptor.forResult( + sourceDir, + compilationSuccessful, + diagnostics.getDiagnostics() + ); + CompilationOutcomeDescriptor expectedResult = CompilationOutcomeDescriptor.forExpectedCompilationResult( + testMethod.getAnnotation( ExpectedCompilationOutcome.class ) + ); + + if ( expectedResult.getCompilationResult() == CompilationResult.SUCCEEDED ) { + assertThat( actualResult.getCompilationResult() ) + .describedAs( "Compilation failed. Diagnostics: " + actualResult.getDiagnostics() ) + .isEqualTo( CompilationResult.SUCCEEDED ); + } + else { + assertThat( actualResult.getCompilationResult() ) + .describedAs( "Compilation succeeded but should have failed." ) + .isEqualTo( CompilationResult.FAILED ); + } + + assertThat( actualResult.getDiagnostics() ).isEqualTo( expectedResult.getDiagnostics() ); } /** diff --git a/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/CompilationResult.java b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/CompilationResult.java new file mode 100644 index 000000000..412857c86 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/CompilationResult.java @@ -0,0 +1,25 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.testutil.compilation.annotation; + +/** + * The result of a compilation. + * + * @author Gunnar Morling + */ +public enum CompilationResult { + SUCCEEDED, FAILED; +} 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 new file mode 100644 index 000000000..f2cb3144d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/Diagnostic.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.testutil.compilation.annotation; + +import javax.tools.Diagnostic.Kind; + +/** + * An expected diagnostic of a compilation. + * + * @author Gunnar Morling + */ +public @interface Diagnostic { + + Class type(); + + Kind kind(); + + int line(); +} 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 new file mode 100644 index 000000000..cf6b5ca71 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/annotation/ExpectedCompilationOutcome.java @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.testutil.compilation.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Specifies the expected outcome of a compilation, comprising the actual result + * and optionally one or more diagnostics. + * + * @author Gunnar Morling + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface ExpectedCompilationOutcome { + CompilationResult value(); + + Diagnostic[] diagnostics(); +} 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 new file mode 100644 index 000000000..0938a943d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/CompilationOutcomeDescriptor.java @@ -0,0 +1,124 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.testutil.compilation.model; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.tools.JavaFileObject; + +import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult; +import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic; +import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome; + +/** + * Represents the outcome of a compilation. + * + * @author Gunnar Morling + */ +public class CompilationOutcomeDescriptor { + + private CompilationResult compilationResult; + private Set diagnostics; + + private CompilationOutcomeDescriptor(CompilationResult compilationResult, + Set diagnostics) { + this.compilationResult = compilationResult; + this.diagnostics = diagnostics; + } + + public static CompilationOutcomeDescriptor forExpectedCompilationResult(ExpectedCompilationOutcome expectedCompilationResult) { + if ( expectedCompilationResult == null ) { + return new CompilationOutcomeDescriptor( + CompilationResult.SUCCEEDED, + Collections.emptySet() + ); + } + else { + Set diagnosticDescriptors = new HashSet(); + for ( Diagnostic diagnostic : expectedCompilationResult.diagnostics() ) { + diagnosticDescriptors.add( DiagnosticDescriptor.forDiagnostic( diagnostic ) ); + } + + return new CompilationOutcomeDescriptor( expectedCompilationResult.value(), diagnosticDescriptors ); + } + } + + public static CompilationOutcomeDescriptor forResult(String sourceDir, boolean compilationSuccessful, List> diagnostics) { + CompilationResult compilationResult = compilationSuccessful ? CompilationResult.SUCCEEDED : CompilationResult.FAILED; + + Set diagnosticDescriptors = new HashSet(); + for ( javax.tools.Diagnostic diagnostic : diagnostics ) { + diagnosticDescriptors.add( DiagnosticDescriptor.forDiagnostic( sourceDir, diagnostic ) ); + } + + return new CompilationOutcomeDescriptor( compilationResult, diagnosticDescriptors ); + } + + public CompilationResult getCompilationResult() { + return compilationResult; + } + + public Set getDiagnostics() { + return diagnostics; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime + * result + + ( ( compilationResult == null ) ? 0 : compilationResult + .hashCode() ); + result = prime * result + + ( ( diagnostics == null ) ? 0 : diagnostics.hashCode() ); + return result; + } + + @Override + public boolean equals(Object obj) { + if ( this == obj ) { + return true; + } + if ( obj == null ) { + return false; + } + if ( getClass() != obj.getClass() ) { + return false; + } + CompilationOutcomeDescriptor other = (CompilationOutcomeDescriptor) obj; + if ( compilationResult != other.compilationResult ) { + return false; + } + if ( diagnostics == null ) { + if ( other.diagnostics != null ) { + return false; + } + } + else if ( !diagnostics.equals( other.diagnostics ) ) { + return false; + } + return true; + } + + @Override + public String toString() { + return "CompilationResultDescriptor [compilationResult=" + + compilationResult + ", diagnostics=" + 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 new file mode 100644 index 000000000..5e96b6f9a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/testutil/compilation/model/DiagnosticDescriptor.java @@ -0,0 +1,128 @@ +/** + * Copyright 2012-2013 Gunnar Morling (http://www.gunnarmorling.de/) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.testutil.compilation.model; + +import java.io.File; +import javax.tools.Diagnostic.Kind; +import javax.tools.JavaFileObject; + +import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic; + +/** + * Represents a diagnostic ocurred during a compilation. + * + * @author Gunnar Morling + */ +public class DiagnosticDescriptor { + + private final String sourceFileName; + private final Kind kind; + private final long line; + private final String message; + + private DiagnosticDescriptor(String sourceFileName, Kind kind, long line, String message) { + this.sourceFileName = sourceFileName; + this.kind = kind; + this.line = line; + this.message = message; + } + + public static DiagnosticDescriptor forDiagnostic(Diagnostic diagnostic) { + String soureFileName = diagnostic.type().getName().replaceAll( "\\.", File.separator ) + ".java"; + return new DiagnosticDescriptor( soureFileName, diagnostic.kind(), diagnostic.line(), "" ); + } + + public static DiagnosticDescriptor forDiagnostic(String sourceDir, javax.tools.Diagnostic diagnostic) { + return new DiagnosticDescriptor( + diagnostic.getSource().getName().substring( sourceDir.length() + 1 ), + diagnostic.getKind(), + diagnostic.getLineNumber(), + "" + ); + } + + public String getSourceFileName() { + return sourceFileName; + } + + public Kind getKind() { + return kind; + } + + public long getLine() { + return line; + } + + public String getMessage() { + return message; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ( ( kind == null ) ? 0 : kind.hashCode() ); + result = prime * result + (int) ( line ^ ( line >>> 32 ) ); + result = prime * result + ( ( message == null ) ? 0 : message.hashCode() ); + result = prime * result + + ( ( sourceFileName == null ) ? 0 : sourceFileName.hashCode() ); + return result; + } + + @Override + public boolean equals(Object obj) { + if ( this == obj ) { + return true; + } + if ( obj == null ) { + return false; + } + if ( getClass() != obj.getClass() ) { + return false; + } + DiagnosticDescriptor other = (DiagnosticDescriptor) obj; + if ( kind != other.kind ) { + return false; + } + if ( line != other.line ) { + return false; + } + if ( message == null ) { + if ( other.message != null ) { + return false; + } + } + else if ( !message.equals( other.message ) ) { + return false; + } + if ( sourceFileName == null ) { + if ( other.sourceFileName != null ) { + return false; + } + } + else if ( !sourceFileName.equals( other.sourceFileName ) ) { + return false; + } + return true; + } + + @Override + public String toString() { + return "DiagnosticDescriptor [sourceFileName=" + sourceFileName + + ", kind=" + kind + ", line=" + line + ", message=" + message + + "]"; + } +}