mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#667 Run all processor tests with both the JDK compiler and the Eclipse compiler.
All generated sources and compilation results are kept in a new directory structure, making manual inspection easier, and also simplifying parallel test-class execution.
This commit is contained in:
parent
af9b54fa4f
commit
aba26328ba
@ -64,7 +64,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.tycho</groupId>
|
<groupId>org.eclipse.tycho</groupId>
|
||||||
<artifactId>tycho-compiler-jdt</artifactId>
|
<artifactId>tycho-compiler-jdt</artifactId>
|
||||||
<version>0.21.0</version>
|
<version>${org.eclipse.tyco.compiler-jdt.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
<org.apache.maven.plugins.surefire.version>2.18.1</org.apache.maven.plugins.surefire.version>
|
<org.apache.maven.plugins.surefire.version>2.18.1</org.apache.maven.plugins.surefire.version>
|
||||||
<org.apache.maven.plugins.javadoc.version>2.10.3</org.apache.maven.plugins.javadoc.version>
|
<org.apache.maven.plugins.javadoc.version>2.10.3</org.apache.maven.plugins.javadoc.version>
|
||||||
<org.springframework.version>4.0.3.RELEASE</org.springframework.version>
|
<org.springframework.version>4.0.3.RELEASE</org.springframework.version>
|
||||||
|
<org.eclipse.tyco.compiler-jdt.version>0.23.1</org.eclipse.tyco.compiler-jdt.version>
|
||||||
<add.release.arguments />
|
<add.release.arguments />
|
||||||
<forkCount>1</forkCount>
|
<forkCount>1</forkCount>
|
||||||
</properties>
|
</properties>
|
||||||
@ -192,6 +193,23 @@
|
|||||||
<version>2.9</version>
|
<version>2.9</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Plexus Eclipse Compiler -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.tycho</groupId>
|
||||||
|
<artifactId>tycho-compiler-jdt</artifactId>
|
||||||
|
<version>${org.eclipse.tyco.compiler-jdt.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.plexus</groupId>
|
||||||
|
<artifactId>plexus-container-default</artifactId>
|
||||||
|
<version>1.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.plexus</groupId>
|
||||||
|
<artifactId>plexus-utils</artifactId>
|
||||||
|
<version>3.0.20</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Project modules -->
|
<!-- Project modules -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
|
@ -84,6 +84,17 @@
|
|||||||
<artifactId>javax.inject</artifactId>
|
<artifactId>javax.inject</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.tycho</groupId>
|
||||||
|
<artifactId>tycho-compiler-jdt</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- plexus-container-default is a runtime-dependency of the tyco-compiler -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.plexus</groupId>
|
||||||
|
<artifactId>plexus-container-default</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Spring -->
|
<!-- Spring -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -109,7 +120,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
@ -126,11 +136,6 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<configuration>
|
|
||||||
<systemPropertyVariables>
|
|
||||||
<mapper.test.output.dir>compilation-tests_fork-${surefire.forkNumber}</mapper.test.output.dir>
|
|
||||||
</systemPropertyVariables>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.internal.processor;
|
package org.mapstruct.ap.internal.processor;
|
||||||
|
|
||||||
|
import static org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism.AUTO_INHERIT_FROM_CONFIG;
|
||||||
|
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||||
|
import static org.mapstruct.ap.internal.util.Collections.join;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -60,10 +64,6 @@ import org.mapstruct.ap.internal.util.Message;
|
|||||||
import org.mapstruct.ap.internal.util.Strings;
|
import org.mapstruct.ap.internal.util.Strings;
|
||||||
import org.mapstruct.ap.internal.version.VersionInformation;
|
import org.mapstruct.ap.internal.version.VersionInformation;
|
||||||
|
|
||||||
import static org.mapstruct.ap.internal.prism.MappingInheritanceStrategyPrism.AUTO_INHERIT_FROM_CONFIG;
|
|
||||||
import static org.mapstruct.ap.internal.util.Collections.first;
|
|
||||||
import static org.mapstruct.ap.internal.util.Collections.join;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ModelElementProcessor} which creates a {@link Mapper} from the given
|
* A {@link ModelElementProcessor} which creates a {@link Mapper} from the given
|
||||||
* list of {@link SourceMethod}s.
|
* list of {@link SourceMethod}s.
|
||||||
@ -173,7 +173,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
TypeElement decoratorElement = (TypeElement) typeUtils.asElement( decoratorPrism.value() );
|
TypeElement decoratorElement = (TypeElement) typeUtils.asElement( decoratorPrism.value() );
|
||||||
|
|
||||||
if ( !typeUtils.isAssignable( decoratorElement.asType(), element.asType() ) ) {
|
if ( !typeUtils.isAssignable( decoratorElement.asType(), element.asType() ) ) {
|
||||||
messager.printMessage( element, decoratorPrism.mirror, Message.DECORATOR_NO_SUBTYPE);
|
messager.printMessage( element, decoratorPrism.mirror, Message.DECORATOR_NO_SUBTYPE );
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MappingMethod> mappingMethods = new ArrayList<MappingMethod>( methods.size() );
|
List<MappingMethod> mappingMethods = new ArrayList<MappingMethod>( methods.size() );
|
||||||
@ -491,8 +491,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
else if ( nameFilteredcandidates.size() > 1 ) {
|
else if ( nameFilteredcandidates.size() > 1 ) {
|
||||||
reportErrorWhenSeveralNamesMatch( nameFilteredcandidates, method, reversePrism );
|
reportErrorWhenSeveralNamesMatch( nameFilteredcandidates, method, reversePrism );
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if ( resultMethod == null ) {
|
|
||||||
reportErrorWhenAmbigousReverseMapping( candidates, method, reversePrism );
|
reportErrorWhenAmbigousReverseMapping( candidates, method, reversePrism );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -571,8 +570,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
else if ( nameFilteredcandidates.size() > 1 ) {
|
else if ( nameFilteredcandidates.size() > 1 ) {
|
||||||
reportErrorWhenSeveralNamesMatch( nameFilteredcandidates, method, forwardPrism );
|
reportErrorWhenSeveralNamesMatch( nameFilteredcandidates, method, forwardPrism );
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if ( resultMethod == null ) {
|
|
||||||
reportErrorWhenAmbigousMapping( candidates, method, forwardPrism );
|
reportErrorWhenAmbigousMapping( candidates, method, forwardPrism );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -675,7 +673,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
|
|||||||
prism.mirror,
|
prism.mirror,
|
||||||
Message.INHERITCONFIGURATION_DUPLICATE_MATCHES,
|
Message.INHERITCONFIGURATION_DUPLICATE_MATCHES,
|
||||||
prism.name(),
|
prism.name(),
|
||||||
Strings.join( candidates, "(), " )
|
Strings.join( candidates, ", " )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,11 +100,11 @@ public enum Message {
|
|||||||
INHERITCONFIGURATION_BOTH( "Method cannot be annotated with both a @InheritConfiguration and @InheritInverseConfiguration." ),
|
INHERITCONFIGURATION_BOTH( "Method cannot be annotated with both a @InheritConfiguration and @InheritInverseConfiguration." ),
|
||||||
INHERITINVERSECONFIGURATION_DUPLICATES( "Several matching inverse methods exist: %s(). Specify a name explicitly." ),
|
INHERITINVERSECONFIGURATION_DUPLICATES( "Several matching inverse methods exist: %s(). Specify a name explicitly." ),
|
||||||
INHERITINVERSECONFIGURATION_INVALID_NAME( "None of the candidates %s() matches given name: \"%s\"." ),
|
INHERITINVERSECONFIGURATION_INVALID_NAME( "None of the candidates %s() matches given name: \"%s\"." ),
|
||||||
INHERITINVERSECONFIGURATION_DUPLICATE_MATCHES( "Given name \"%s\" matches several candidate methods: %s()." ),
|
INHERITINVERSECONFIGURATION_DUPLICATE_MATCHES( "Given name \"%s\" matches several candidate methods: %s." ),
|
||||||
INHERITINVERSECONFIGURATION_NO_NAME_MATCH( "Given name \"%s\" does not match the only candidate. Did you mean: \"%s\"." ),
|
INHERITINVERSECONFIGURATION_NO_NAME_MATCH( "Given name \"%s\" does not match the only candidate. Did you mean: \"%s\"." ),
|
||||||
INHERITCONFIGURATION_DUPLICATES( "Several matching methods exist: %s(). Specify a name explicitly." ),
|
INHERITCONFIGURATION_DUPLICATES( "Several matching methods exist: %s(). Specify a name explicitly." ),
|
||||||
INHERITCONFIGURATION_INVALIDNAME( "None of the candidates %s() matches given name: \"%s\"." ),
|
INHERITCONFIGURATION_INVALIDNAME( "None of the candidates %s() matches given name: \"%s\"." ),
|
||||||
INHERITCONFIGURATION_DUPLICATE_MATCHES( "Given name \"%s\" matches several candidate methods: %s()." ),
|
INHERITCONFIGURATION_DUPLICATE_MATCHES( "Given name \"%s\" matches several candidate methods: %s." ),
|
||||||
INHERITCONFIGURATION_NO_NAME_MATCH( "Given name \"%s\" does not match the only candidate. Did you mean: \"%s\"." ),
|
INHERITCONFIGURATION_NO_NAME_MATCH( "Given name \"%s\" does not match the only candidate. Did you mean: \"%s\"." ),
|
||||||
INHERITCONFIGURATION_MULTIPLE_PROTOTYPE_METHODS_MATCH( "More than one configuration prototype method is applicable. Use @InheritConfiguration to select one of them explicitly: %s." ),
|
INHERITCONFIGURATION_MULTIPLE_PROTOTYPE_METHODS_MATCH( "More than one configuration prototype method is applicable. Use @InheritConfiguration to select one of them explicitly: %s." ),
|
||||||
INHERITCONFIGURATION_CYCLE( "Cycle detected while evaluating inherited configurations. Inheritance path: %s" );
|
INHERITCONFIGURATION_CYCLE( "Cycle detected while evaluating inherited configurations. Inheritance path: %s" );
|
||||||
@ -113,12 +113,12 @@ public enum Message {
|
|||||||
private final String description;
|
private final String description;
|
||||||
private final Diagnostic.Kind kind;
|
private final Diagnostic.Kind kind;
|
||||||
|
|
||||||
private Message(String description) {
|
Message(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.kind = Diagnostic.Kind.ERROR;
|
this.kind = Diagnostic.Kind.ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Message(String description, Diagnostic.Kind kind) {
|
Message(String description, Diagnostic.Kind kind) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.test.defaultvalue;
|
package org.mapstruct.ap.test.defaultvalue;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mapstruct.ap.testutil.IssueKey;
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
@ -27,8 +29,6 @@ import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
|
|||||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||||
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||||
|
|
||||||
import java.text.ParseException;
|
|
||||||
|
|
||||||
import static org.fest.assertions.Assertions.assertThat;
|
import static org.fest.assertions.Assertions.assertThat;
|
||||||
|
|
||||||
@IssueKey( "600" )
|
@IssueKey( "600" )
|
||||||
@ -136,6 +136,10 @@ public class DefaultValueTest {
|
|||||||
line = 33,
|
line = 33,
|
||||||
messageRegExp = "Constant and default value are both defined in @Mapping,"
|
messageRegExp = "Constant and default value are both defined in @Mapping,"
|
||||||
+ " either define a defaultValue or a constant." ),
|
+ " either define a defaultValue or a constant." ),
|
||||||
|
@Diagnostic(type = ErroneousMapper.class,
|
||||||
|
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||||
|
line = 33,
|
||||||
|
messageRegExp = "Can't map property \".*Region region\" to \".*String region\"\\. Consider")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public void errorOnDefaultValueAndConstant() throws ParseException {
|
public void errorOnDefaultValueAndConstant() throws ParseException {
|
||||||
@ -154,6 +158,10 @@ public class DefaultValueTest {
|
|||||||
line = 33,
|
line = 33,
|
||||||
messageRegExp = "Expression and default value are both defined in @Mapping,"
|
messageRegExp = "Expression and default value are both defined in @Mapping,"
|
||||||
+ " either define a defaultValue or an expression." ),
|
+ " either define a defaultValue or an expression." ),
|
||||||
|
@Diagnostic(type = ErroneousMapper2.class,
|
||||||
|
kind = javax.tools.Diagnostic.Kind.ERROR,
|
||||||
|
line = 33,
|
||||||
|
messageRegExp = "Can't map property \".*Region region\" to \".*String region\"\\. Consider")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public void errorOnDefaultValueAndExpression() throws ParseException {
|
public void errorOnDefaultValueAndExpression() throws ParseException {
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package org.mapstruct.ap.test.erroneous.annotationnotfound;
|
package org.mapstruct.ap.test.erroneous.annotationnotfound;
|
||||||
|
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mapstruct.ap.testutil.IssueKey;
|
import org.mapstruct.ap.testutil.IssueKey;
|
||||||
@ -45,9 +46,7 @@ public class AnnotationNotFoundTest {
|
|||||||
@Diagnostic( type = ErroneousMapper.class,
|
@Diagnostic( type = ErroneousMapper.class,
|
||||||
kind = Kind.ERROR,
|
kind = Kind.ERROR,
|
||||||
line = 30,
|
line = 30,
|
||||||
messageRegExp = "cannot find symbol\n"
|
messageRegExp = "NotFoundAnnotation")
|
||||||
+ " symbol: class NotFoundAnnotation\n"
|
|
||||||
+ " location: interface org.mapstruct.ap.test.erroneous.annotationnotfound.ErroneousMapper" )
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public void shouldFailToGenerateMappings() {
|
public void shouldFailToGenerateMappings() {
|
||||||
|
@ -108,8 +108,8 @@ public class InheritInverseConfigurationTest {
|
|||||||
@Diagnostic(type = SourceTargetMapperAmbiguous3.class,
|
@Diagnostic(type = SourceTargetMapperAmbiguous3.class,
|
||||||
kind = Kind.ERROR,
|
kind = Kind.ERROR,
|
||||||
line = 50,
|
line = 50,
|
||||||
messageRegExp = "Given name \"forward\" matches several candidate methods: .*forward\\(.*\\), "
|
messageRegExp = "Given name \"forward\" matches several candidate methods: .*forward\\(.+\\), "
|
||||||
+ ".*forward\\(.*\\)"),
|
+ ".*forward\\(.+\\)"),
|
||||||
@Diagnostic(type = SourceTargetMapperAmbiguous3.class,
|
@Diagnostic(type = SourceTargetMapperAmbiguous3.class,
|
||||||
kind = Kind.WARNING,
|
kind = Kind.WARNING,
|
||||||
line = 55,
|
line = 55,
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.test.severalsources;
|
package org.mapstruct.ap.test.severalsources;
|
||||||
|
|
||||||
import javax.lang.model.SourceVersion;
|
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -145,7 +144,7 @@ public class SeveralSourceParametersTest {
|
|||||||
assertThat( deliveryAddress.getZipCode() ).isEqualTo( 12345 );
|
assertThat( deliveryAddress.getZipCode() ).isEqualTo( 12345 );
|
||||||
assertThat( deliveryAddress.getHouseNumber() ).isEqualTo( 42 );
|
assertThat( deliveryAddress.getHouseNumber() ).isEqualTo( 42 );
|
||||||
assertThat( deliveryAddress.getDescription() ).isEqualTo( "An actor" );
|
assertThat( deliveryAddress.getDescription() ).isEqualTo( "An actor" );
|
||||||
assertThat( deliveryAddress.getStreet()).isEqualTo( "Main street" );
|
assertThat( deliveryAddress.getStreet() ).isEqualTo( "Main street" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -154,21 +153,18 @@ public class SeveralSourceParametersTest {
|
|||||||
@ExpectedCompilationOutcome(
|
@ExpectedCompilationOutcome(
|
||||||
value = CompilationResult.FAILED,
|
value = CompilationResult.FAILED,
|
||||||
diagnostics = {
|
diagnostics = {
|
||||||
@Diagnostic(type = ErroneousSourceTargetMapper.class,
|
|
||||||
kind = Kind.ERROR,
|
|
||||||
line = 29,
|
|
||||||
messageRegExp = "Several possible source properties for target property \"description\".",
|
|
||||||
javaVersions = { SourceVersion.RELEASE_6 } ),
|
|
||||||
@Diagnostic(type = ErroneousSourceTargetMapper.class,
|
|
||||||
kind = Kind.ERROR,
|
|
||||||
line = 29,
|
|
||||||
messageRegExp = "Several possible source properties for target property \"zipCode\".",
|
|
||||||
javaVersions = { SourceVersion.RELEASE_6 } ),
|
|
||||||
@Diagnostic(type = ErroneousSourceTargetMapper.class,
|
@Diagnostic(type = ErroneousSourceTargetMapper.class,
|
||||||
kind = Kind.ERROR,
|
kind = Kind.ERROR,
|
||||||
line = 29,
|
line = 29,
|
||||||
messageRegExp = "Several possible source properties for target property \"street\"."),
|
messageRegExp = "Several possible source properties for target property \"street\"."),
|
||||||
|
@Diagnostic(type = ErroneousSourceTargetMapper.class,
|
||||||
|
kind = Kind.ERROR,
|
||||||
|
line = 29,
|
||||||
|
messageRegExp = "Several possible source properties for target property \"zipCode\"."),
|
||||||
|
@Diagnostic(type = ErroneousSourceTargetMapper.class,
|
||||||
|
kind = Kind.ERROR,
|
||||||
|
line = 29,
|
||||||
|
messageRegExp = "Several possible source properties for target property \"description\".")
|
||||||
})
|
})
|
||||||
public void shouldFailToGenerateMappingsForAmbigiousSourceProperty() {
|
public void shouldFailToGenerateMappingsForAmbigiousSourceProperty() {
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ public class InheritConfigurationTest {
|
|||||||
assertThat( createdTarget ).isNotNull();
|
assertThat( createdTarget ).isNotNull();
|
||||||
assertThat( createdTarget.getStringPropY() ).isEqualTo( "1" );
|
assertThat( createdTarget.getStringPropY() ).isEqualTo( "1" );
|
||||||
assertThat( createdTarget.getIntegerPropY() ).isEqualTo( 2 );
|
assertThat( createdTarget.getIntegerPropY() ).isEqualTo( 2 );
|
||||||
assertThat( createdTarget.getNestedResultProp() ).isEqualTo( "nested");
|
assertThat( createdTarget.getNestedResultProp() ).isEqualTo( "nested" );
|
||||||
assertThat( createdTarget.getExpressionProp() ).isEqualTo( "expression" );
|
assertThat( createdTarget.getExpressionProp() ).isEqualTo( "expression" );
|
||||||
assertThat( createdTarget.getConstantProp() ).isEqualTo( "constant" );
|
assertThat( createdTarget.getConstantProp() ).isEqualTo( "constant" );
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ public class InheritConfigurationTest {
|
|||||||
assertThat( createdTarget ).isNotNull();
|
assertThat( createdTarget ).isNotNull();
|
||||||
assertThat( createdTarget.getStringPropY() ).isEqualTo( "1" );
|
assertThat( createdTarget.getStringPropY() ).isEqualTo( "1" );
|
||||||
assertThat( createdTarget.getIntegerPropY() ).isEqualTo( 2 );
|
assertThat( createdTarget.getIntegerPropY() ).isEqualTo( 2 );
|
||||||
assertThat( createdTarget.getNestedResultProp() ).isEqualTo( "nested");
|
assertThat( createdTarget.getNestedResultProp() ).isEqualTo( "nested" );
|
||||||
assertThat( createdTarget.getExpressionProp() ).isEqualTo( "expression" );
|
assertThat( createdTarget.getExpressionProp() ).isEqualTo( "expression" );
|
||||||
assertThat( createdTarget.getConstantProp() ).isEqualTo( "constant" );
|
assertThat( createdTarget.getConstantProp() ).isEqualTo( "constant" );
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ public class InheritConfigurationTest {
|
|||||||
assertThat( createdTarget ).isNotNull();
|
assertThat( createdTarget ).isNotNull();
|
||||||
assertThat( createdTarget.getStringPropY() ).isEqualTo( "1" );
|
assertThat( createdTarget.getStringPropY() ).isEqualTo( "1" );
|
||||||
assertThat( createdTarget.getIntegerPropY() ).isEqualTo( 2 );
|
assertThat( createdTarget.getIntegerPropY() ).isEqualTo( 2 );
|
||||||
assertThat( createdTarget.getNestedResultProp() ).isEqualTo( "nested");
|
assertThat( createdTarget.getNestedResultProp() ).isEqualTo( "nested" );
|
||||||
assertThat( createdTarget.getExpressionProp() ).isEqualTo( "expression" );
|
assertThat( createdTarget.getExpressionProp() ).isEqualTo( "expression" );
|
||||||
assertThat( createdTarget.getConstantProp() ).isEqualTo( "constant" );
|
assertThat( createdTarget.getConstantProp() ).isEqualTo( "constant" );
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ public class InheritConfigurationTest {
|
|||||||
kind = Kind.ERROR,
|
kind = Kind.ERROR,
|
||||||
line = 54,
|
line = 54,
|
||||||
messageRegExp = "Given name \"forwardCreate\" matches several candidate methods: "
|
messageRegExp = "Given name \"forwardCreate\" matches several candidate methods: "
|
||||||
+ ".*forwardCreate.*\\(\\), .*forwardCreate.*\\(\\)"),
|
+ ".*forwardCreate.*, .*forwardCreate.*"),
|
||||||
@Diagnostic(type = SourceTargetMapperAmbiguous3.class,
|
@Diagnostic(type = SourceTargetMapperAmbiguous3.class,
|
||||||
kind = Kind.WARNING,
|
kind = Kind.WARNING,
|
||||||
line = 55,
|
line = 55,
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.testutil.compilation.annotation;
|
package org.mapstruct.ap.testutil.compilation.annotation;
|
||||||
|
|
||||||
import javax.lang.model.SourceVersion;
|
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,11 +57,4 @@ public @interface Diagnostic {
|
|||||||
* diagnostic.
|
* diagnostic.
|
||||||
*/
|
*/
|
||||||
String messageRegExp() default ".*";
|
String messageRegExp() default ".*";
|
||||||
|
|
||||||
/**
|
|
||||||
* The java version for which this this diagnostic is valid.
|
|
||||||
*
|
|
||||||
* @return versions for which this Diagnostic should be evaluated. Default it evaluates for all
|
|
||||||
*/
|
|
||||||
SourceVersion[] javaVersions() default { };
|
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,13 @@ package org.mapstruct.ap.testutil.compilation.model;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.lang.model.SourceVersion;
|
|
||||||
import javax.tools.Diagnostic;
|
import javax.tools.Diagnostic;
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
|
|
||||||
|
import org.codehaus.plexus.compiler.CompilerMessage;
|
||||||
|
import org.codehaus.plexus.compiler.CompilerResult;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||||
|
|
||||||
@ -57,27 +59,13 @@ public class CompilationOutcomeDescriptor {
|
|||||||
List<DiagnosticDescriptor> diagnosticDescriptors = new ArrayList<DiagnosticDescriptor>();
|
List<DiagnosticDescriptor> diagnosticDescriptors = new ArrayList<DiagnosticDescriptor>();
|
||||||
for ( org.mapstruct.ap.testutil.compilation.annotation.Diagnostic diagnostic :
|
for ( org.mapstruct.ap.testutil.compilation.annotation.Diagnostic diagnostic :
|
||||||
expectedCompilationResult.diagnostics() ) {
|
expectedCompilationResult.diagnostics() ) {
|
||||||
if ( requiresEvaluation( diagnostic.javaVersions() ) ) {
|
diagnosticDescriptors.add( DiagnosticDescriptor.forDiagnostic( diagnostic ) );
|
||||||
diagnosticDescriptors.add( DiagnosticDescriptor.forDiagnostic( diagnostic ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CompilationOutcomeDescriptor( expectedCompilationResult.value(), diagnosticDescriptors );
|
return new CompilationOutcomeDescriptor( expectedCompilationResult.value(), diagnosticDescriptors );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean requiresEvaluation(SourceVersion[] sourceVersions) {
|
|
||||||
if ( sourceVersions.length == 0 ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for ( SourceVersion sourceVersion : sourceVersions ) {
|
|
||||||
if ( SourceVersion.latestSupported().equals( sourceVersion ) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CompilationOutcomeDescriptor forResult(String sourceDir, boolean compilationSuccessful,
|
public static CompilationOutcomeDescriptor forResult(String sourceDir, boolean compilationSuccessful,
|
||||||
List<Diagnostic<? extends JavaFileObject>> diagnostics) {
|
List<Diagnostic<? extends JavaFileObject>> diagnostics) {
|
||||||
CompilationResult compilationResult =
|
CompilationResult compilationResult =
|
||||||
@ -94,6 +82,21 @@ public class CompilationOutcomeDescriptor {
|
|||||||
return new CompilationOutcomeDescriptor( compilationResult, diagnosticDescriptors );
|
return new CompilationOutcomeDescriptor( compilationResult, diagnosticDescriptors );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CompilationOutcomeDescriptor forResult(String sourceDir, CompilerResult compilerResult) {
|
||||||
|
CompilationResult compilationResult =
|
||||||
|
compilerResult.isSuccess() ? CompilationResult.SUCCEEDED : CompilationResult.FAILED;
|
||||||
|
|
||||||
|
List<DiagnosticDescriptor> diagnosticDescriptors = new ArrayList<DiagnosticDescriptor>();
|
||||||
|
|
||||||
|
for ( CompilerMessage message : compilerResult.getCompilerMessages() ) {
|
||||||
|
if ( message.getKind() != CompilerMessage.Kind.NOTE ) {
|
||||||
|
diagnosticDescriptors.add( DiagnosticDescriptor.forCompilerMessage( sourceDir, message ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CompilationOutcomeDescriptor( compilationResult, diagnosticDescriptors );
|
||||||
|
}
|
||||||
|
|
||||||
public CompilationResult getCompilationResult() {
|
public CompilationResult getCompilationResult() {
|
||||||
return compilationResult;
|
return compilationResult;
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,11 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
import javax.tools.Diagnostic.Kind;
|
import javax.tools.Diagnostic.Kind;
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
|
|
||||||
|
import org.codehaus.plexus.compiler.CompilerMessage;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
|
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,6 +70,34 @@ public class DiagnosticDescriptor {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DiagnosticDescriptor forCompilerMessage(String sourceDir, CompilerMessage compilerMessage) {
|
||||||
|
String[] lines = compilerMessage.getMessage().split( System.lineSeparator() );
|
||||||
|
String message = lines[3];
|
||||||
|
|
||||||
|
return new DiagnosticDescriptor(
|
||||||
|
removeSourceDirPrefix( sourceDir, compilerMessage.getFile() ),
|
||||||
|
toJavaxKind( compilerMessage.getKind() ),
|
||||||
|
Long.valueOf( compilerMessage.getStartLine() ),
|
||||||
|
message );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Kind toJavaxKind(CompilerMessage.Kind kind) {
|
||||||
|
switch ( kind ) {
|
||||||
|
case ERROR:
|
||||||
|
return Kind.ERROR;
|
||||||
|
case MANDATORY_WARNING:
|
||||||
|
return Kind.MANDATORY_WARNING;
|
||||||
|
case NOTE:
|
||||||
|
return Kind.NOTE;
|
||||||
|
case OTHER:
|
||||||
|
return Kind.OTHER;
|
||||||
|
case WARNING:
|
||||||
|
return Kind.WARNING;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static String getSourceName(String sourceDir, javax.tools.Diagnostic<? extends JavaFileObject> diagnostic) {
|
private static String getSourceName(String sourceDir, javax.tools.Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||||
if ( diagnostic.getSource() == null ) {
|
if ( diagnostic.getSource() == null ) {
|
||||||
return null;
|
return null;
|
||||||
@ -77,15 +107,19 @@ public class DiagnosticDescriptor {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
String sourceName = new File( uri ).getCanonicalPath();
|
String sourceName = new File( uri ).getCanonicalPath();
|
||||||
return sourceName.length() > sourceDir.length() ?
|
return removeSourceDirPrefix( sourceDir, sourceName );
|
||||||
sourceName.substring( sourceDir.length() + 1 ) :
|
|
||||||
sourceName;
|
|
||||||
}
|
}
|
||||||
catch ( IOException e ) {
|
catch ( IOException e ) {
|
||||||
throw new RuntimeException( e );
|
throw new RuntimeException( e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String removeSourceDirPrefix(String sourceDir, String sourceName) {
|
||||||
|
return sourceName.length() > sourceDir.length() ?
|
||||||
|
sourceName.substring( sourceDir.length() + 1 ) :
|
||||||
|
sourceName;
|
||||||
|
}
|
||||||
|
|
||||||
private static URI getUri(javax.tools.Diagnostic<? extends JavaFileObject> diagnostic) {
|
private static URI getUri(javax.tools.Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||||
URI uri = diagnostic.getSource().toUri();
|
URI uri = diagnostic.getSource().toUri();
|
||||||
|
|
||||||
|
@ -18,12 +18,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.testutil.runner;
|
package org.mapstruct.ap.testutil.runner;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.runner.Description;
|
||||||
|
import org.junit.runner.Runner;
|
||||||
|
import org.junit.runner.notification.RunNotifier;
|
||||||
import org.junit.runners.BlockJUnit4ClassRunner;
|
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||||
import org.junit.runners.model.FrameworkMethod;
|
import org.junit.runners.ParentRunner;
|
||||||
import org.junit.runners.model.Statement;
|
|
||||||
import org.junit.runners.model.TestClass;
|
|
||||||
import org.mapstruct.ap.testutil.WithClasses;
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||||
@ -31,7 +33,7 @@ import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
|||||||
/**
|
/**
|
||||||
* A JUnit4 runner for Annotation Processor tests.
|
* A JUnit4 runner for Annotation Processor tests.
|
||||||
* <p>
|
* <p>
|
||||||
* Test classes and test methods are safe to be executed in parallel.
|
* Test classes are safe to be executed in parallel, the methods must not executed in parallel.
|
||||||
* <p>
|
* <p>
|
||||||
* The classes to be compiled for a given test method must be specified via {@link WithClasses}. In addition the
|
* The classes to be compiled for a given test method must be specified via {@link WithClasses}. In addition the
|
||||||
* following things can be configured optionally :
|
* following things can be configured optionally :
|
||||||
@ -44,11 +46,8 @@ import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
|||||||
* @author Gunnar Morling
|
* @author Gunnar Morling
|
||||||
* @author Andreas Gudian
|
* @author Andreas Gudian
|
||||||
*/
|
*/
|
||||||
public class AnnotationProcessorTestRunner extends BlockJUnit4ClassRunner {
|
public class AnnotationProcessorTestRunner extends ParentRunner<Runner> {
|
||||||
static final ModifiableURLClassLoader TEST_CLASS_LOADER = new ModifiableURLClassLoader();
|
private final List<Runner> runners;
|
||||||
private final Class<?> klass;
|
|
||||||
private Class<?> klassToUse;
|
|
||||||
private ReplacableTestClass replacableTestClass;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param klass the test class
|
* @param klass the test class
|
||||||
@ -57,72 +56,24 @@ public class AnnotationProcessorTestRunner extends BlockJUnit4ClassRunner {
|
|||||||
*/
|
*/
|
||||||
public AnnotationProcessorTestRunner(Class<?> klass) throws Exception {
|
public AnnotationProcessorTestRunner(Class<?> klass) throws Exception {
|
||||||
super( klass );
|
super( klass );
|
||||||
this.klass = klass;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
runners = Arrays.<Runner> asList(
|
||||||
* newly loads the class with the test class loader and sets that loader as context class loader of the thread
|
new InnerAnnotationProcessorRunner( klass, Compiler.JDK ),
|
||||||
*
|
new InnerAnnotationProcessorRunner( klass, Compiler.ECLIPSE ) );
|
||||||
* @param klass the class to replace
|
|
||||||
*
|
|
||||||
* @return the class loaded with the test class loader
|
|
||||||
*/
|
|
||||||
private static Class<?> replaceClassLoaderAndClass(Class<?> klass) {
|
|
||||||
replaceContextClassLoader( klass );
|
|
||||||
|
|
||||||
try {
|
|
||||||
return Thread.currentThread().getContextClassLoader().loadClass( klass.getName() );
|
|
||||||
}
|
|
||||||
catch ( ClassNotFoundException e ) {
|
|
||||||
throw new RuntimeException( e );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void replaceContextClassLoader(Class<?> klass) {
|
|
||||||
String classFileName = klass.getName().replace( ".", "/" ) + ".class";
|
|
||||||
URL classResource = klass.getClassLoader().getResource( classFileName );
|
|
||||||
String fullyQualifiedUrl = classResource.toExternalForm();
|
|
||||||
String basePath = fullyQualifiedUrl.substring( 0, fullyQualifiedUrl.length() - classFileName.length() );
|
|
||||||
|
|
||||||
ModifiableURLClassLoader testClassLoader = new ModifiableURLClassLoader();
|
|
||||||
testClassLoader.addURL( basePath );
|
|
||||||
|
|
||||||
Thread.currentThread().setContextClassLoader( testClassLoader );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TestClass createTestClass(final Class<?> testClass) {
|
protected List<Runner> getChildren() {
|
||||||
replacableTestClass = new ReplacableTestClass( testClass );
|
return runners;
|
||||||
return replacableTestClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FrameworkMethod replaceFrameworkMethod(FrameworkMethod m) {
|
|
||||||
try {
|
|
||||||
return new FrameworkMethod(
|
|
||||||
klassToUse.getDeclaredMethod( m.getName(), m.getMethod().getParameterTypes() ) );
|
|
||||||
}
|
|
||||||
catch ( NoSuchMethodException e ) {
|
|
||||||
throw new RuntimeException( e );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Statement methodBlock(FrameworkMethod method) {
|
protected Description describeChild(Runner child) {
|
||||||
CompilingStatement statement = new CompilingStatement( method );
|
return child.getDescription();
|
||||||
if ( statement.needsRecompilation() ) {
|
|
||||||
klassToUse = replaceClassLoaderAndClass( klass );
|
|
||||||
|
|
||||||
replacableTestClass.replaceClass( klassToUse );
|
|
||||||
}
|
|
||||||
|
|
||||||
method = replaceFrameworkMethod( method );
|
|
||||||
|
|
||||||
Statement next = super.methodBlock( method );
|
|
||||||
|
|
||||||
statement.setNextStatement( next );
|
|
||||||
|
|
||||||
return statement;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void runChild(Runner child, RunNotifier notifier) {
|
||||||
|
child.run( notifier );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* 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.runner;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor;
|
||||||
|
|
||||||
|
class CompilationCache {
|
||||||
|
private String lastSourceOutputDir;
|
||||||
|
private CompilationRequest lastRequest;
|
||||||
|
private CompilationOutcomeDescriptor lastResult;
|
||||||
|
|
||||||
|
public String getLastSourceOutputDir() {
|
||||||
|
return lastSourceOutputDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastSourceOutputDir(String lastSourceOutputDir) {
|
||||||
|
this.lastSourceOutputDir = lastSourceOutputDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompilationRequest getLastRequest() {
|
||||||
|
return lastRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(CompilationRequest lastRequest, CompilationOutcomeDescriptor lastResult) {
|
||||||
|
this.lastRequest = lastRequest;
|
||||||
|
this.lastResult = lastResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompilationOutcomeDescriptor getLastResult() {
|
||||||
|
return lastResult;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* 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.runner;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a compilation task for a number of sources with given processor options.
|
||||||
|
*/
|
||||||
|
class CompilationRequest {
|
||||||
|
private final Set<Class<?>> sourceClasses;
|
||||||
|
private final List<String> processorOptions;
|
||||||
|
|
||||||
|
CompilationRequest(Set<Class<?>> sourceClasses, List<String> processorOptions) {
|
||||||
|
this.sourceClasses = sourceClasses;
|
||||||
|
this.processorOptions = processorOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ( ( processorOptions == null ) ? 0 : processorOptions.hashCode() );
|
||||||
|
result = prime * result + ( ( sourceClasses == null ) ? 0 : sourceClasses.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;
|
||||||
|
}
|
||||||
|
CompilationRequest other = (CompilationRequest) obj;
|
||||||
|
|
||||||
|
return processorOptions.equals( other.processorOptions ) && sourceClasses.equals( other.sourceClasses );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Class<?>> getSourceClasses() {
|
||||||
|
return sourceClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getProcessorOptions() {
|
||||||
|
return processorOptions;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* 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.runner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andreas Gudian
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum Compiler {
|
||||||
|
JDK, ECLIPSE;
|
||||||
|
}
|
@ -31,19 +31,9 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import javax.tools.DiagnosticCollector;
|
|
||||||
import javax.tools.JavaCompiler;
|
|
||||||
import javax.tools.JavaCompiler.CompilationTask;
|
|
||||||
import javax.tools.JavaFileObject;
|
|
||||||
import javax.tools.StandardJavaFileManager;
|
|
||||||
import javax.tools.StandardLocation;
|
|
||||||
import javax.tools.ToolProvider;
|
|
||||||
|
|
||||||
import org.junit.runners.model.FrameworkMethod;
|
import org.junit.runners.model.FrameworkMethod;
|
||||||
import org.junit.runners.model.Statement;
|
import org.junit.runners.model.Statement;
|
||||||
import org.mapstruct.ap.MappingProcessor;
|
|
||||||
import org.mapstruct.ap.testutil.WithClasses;
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
|
||||||
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||||
@ -67,58 +57,34 @@ import static org.fest.assertions.Assertions.assertThat;
|
|||||||
*
|
*
|
||||||
* @author Andreas Gudian
|
* @author Andreas Gudian
|
||||||
*/
|
*/
|
||||||
class CompilingStatement extends Statement {
|
abstract class CompilingStatement extends Statement {
|
||||||
|
|
||||||
/**
|
private static final String TARGET_COMPILATION_TESTS = "/target/compilation-tests/";
|
||||||
* Property to specify the sub-directory below /target/ where the generated files are placed
|
|
||||||
*/
|
|
||||||
public static final String MAPPER_TEST_OUTPUT_DIR_PROPERTY = "mapper.test.output.dir";
|
|
||||||
private static final String TARGET_COMPILATION_TESTS = "/target/"
|
|
||||||
+ System.getProperty( MAPPER_TEST_OUTPUT_DIR_PROPERTY, "compilation-tests" ) + "_thread-";
|
|
||||||
|
|
||||||
private static final String SOURCE_DIR = getBasePath() + "/src/test/java";
|
|
||||||
|
|
||||||
private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
|
private static final String LINE_SEPARATOR = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
private static final DiagnosticDescriptorComparator COMPARATOR = new DiagnosticDescriptorComparator();
|
private static final DiagnosticDescriptorComparator COMPARATOR = new DiagnosticDescriptorComparator();
|
||||||
|
|
||||||
private static final ThreadLocal<Integer> THREAD_NUMBER = new ThreadLocal<Integer>() {
|
protected static final String SOURCE_DIR = getBasePath() + "/src/test/java";
|
||||||
private final AtomicInteger nextThreadId = new AtomicInteger( 0 );
|
|
||||||
|
|
||||||
@Override
|
protected static final List<String> COMPILER_CLASSPATH = buildCompilerClasspath();
|
||||||
protected Integer initialValue() {
|
|
||||||
return nextThreadId.getAndIncrement();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Caches the outcome of given compilations. That way we avoid the repeated compilation of the same source files for
|
|
||||||
* several test methods of one test class.
|
|
||||||
*/
|
|
||||||
private static final ThreadLocal<CompilationCache> COMPILATION_CACHE = new ThreadLocal<CompilationCache>() {
|
|
||||||
@Override
|
|
||||||
protected CompilationCache initialValue() {
|
|
||||||
return new CompilationCache();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final List<File> COMPILER_CLASSPATH = buildCompilerClasspath();
|
|
||||||
|
|
||||||
private Statement next;
|
|
||||||
private final FrameworkMethod method;
|
private final FrameworkMethod method;
|
||||||
|
private final CompilationCache compilationCache;
|
||||||
|
private Statement next;
|
||||||
|
|
||||||
private JavaCompiler compiler;
|
|
||||||
private String classOutputDir;
|
private String classOutputDir;
|
||||||
private String sourceOutputDir;
|
private String sourceOutputDir;
|
||||||
private CompilationRequest compilationRequest;
|
private CompilationRequest compilationRequest;
|
||||||
|
|
||||||
public CompilingStatement(FrameworkMethod method) {
|
CompilingStatement(FrameworkMethod method, CompilationCache compilationCache) {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
|
this.compilationCache = compilationCache;
|
||||||
|
|
||||||
this.compilationRequest = new CompilationRequest( getTestClasses(), getProcessorOptions() );
|
this.compilationRequest = new CompilationRequest( getTestClasses(), getProcessorOptions() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNextStatement(Statement next) {
|
void setNextStatement(Statement next) {
|
||||||
this.next = next;
|
this.next = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,29 +92,33 @@ class CompilingStatement extends Statement {
|
|||||||
public void evaluate() throws Throwable {
|
public void evaluate() throws Throwable {
|
||||||
generateMapperImplementation();
|
generateMapperImplementation();
|
||||||
|
|
||||||
|
GeneratedSource.setCompilingStatement( this );
|
||||||
next.evaluate();
|
next.evaluate();
|
||||||
|
GeneratedSource.clearCompilingStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getSourceOutputDir() {
|
String getSourceOutputDir() {
|
||||||
return COMPILATION_CACHE.get().lastSourceOutputDir;
|
return compilationCache.getLastSourceOutputDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setupCompiler() throws Exception {
|
protected void setupDirectories() throws Exception {
|
||||||
compiler = ToolProvider.getSystemJavaCompiler();
|
String compilationRoot = getBasePath()
|
||||||
|
+ TARGET_COMPILATION_TESTS
|
||||||
|
+ method.getDeclaringClass().getName()
|
||||||
|
+ "/" + method.getName()
|
||||||
|
+ getPathSuffix();
|
||||||
|
|
||||||
String basePath = getBasePath();
|
classOutputDir = compilationRoot + "/classes";
|
||||||
|
sourceOutputDir = compilationRoot + "/generated-sources";
|
||||||
Integer i = THREAD_NUMBER.get();
|
|
||||||
|
|
||||||
classOutputDir = basePath + TARGET_COMPILATION_TESTS + i + "/classes";
|
|
||||||
sourceOutputDir = basePath + TARGET_COMPILATION_TESTS + i + "/generated-sources/mapping";
|
|
||||||
|
|
||||||
createOutputDirs();
|
createOutputDirs();
|
||||||
|
|
||||||
( (ModifiableURLClassLoader) Thread.currentThread().getContextClassLoader() ).addOutputDir( classOutputDir );
|
( (ModifiableURLClassLoader) Thread.currentThread().getContextClassLoader() ).addOutputDir( classOutputDir );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<File> buildCompilerClasspath() {
|
protected abstract String getPathSuffix();
|
||||||
|
|
||||||
|
private static List<String> buildCompilerClasspath() {
|
||||||
String[] bootClasspath =
|
String[] bootClasspath =
|
||||||
System.getProperty( "java.class.path" ).split( System.getProperty( "path.separator" ) );
|
System.getProperty( "java.class.path" ).split( System.getProperty( "path.separator" ) );
|
||||||
String fs = System.getProperty( "file.separator" );
|
String fs = System.getProperty( "file.separator" );
|
||||||
@ -166,10 +136,10 @@ class CompilingStatement extends Statement {
|
|||||||
"spring-context",
|
"spring-context",
|
||||||
"joda-time" };
|
"joda-time" };
|
||||||
|
|
||||||
List<File> classpath = new ArrayList<File>();
|
List<String> classpath = new ArrayList<String>();
|
||||||
for ( String path : bootClasspath ) {
|
for ( String path : bootClasspath ) {
|
||||||
if ( !path.contains( testClasses ) && isWhitelisted( path, whitelist ) ) {
|
if ( !path.contains( testClasses ) && isWhitelisted( path, whitelist ) ) {
|
||||||
classpath.add( new File( path ) );
|
classpath.add( path );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,14 +156,8 @@ class CompilingStatement extends Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void generateMapperImplementation() throws Exception {
|
protected void generateMapperImplementation() throws Exception {
|
||||||
CompilationResultHolder compilationResult = compile();
|
CompilationOutcomeDescriptor actualResult = compile();
|
||||||
|
|
||||||
CompilationOutcomeDescriptor actualResult =
|
|
||||||
CompilationOutcomeDescriptor.forResult(
|
|
||||||
SOURCE_DIR,
|
|
||||||
compilationResult.compilationSuccessful,
|
|
||||||
compilationResult.diagnostics.getDiagnostics()
|
|
||||||
);
|
|
||||||
CompilationOutcomeDescriptor expectedResult =
|
CompilationOutcomeDescriptor expectedResult =
|
||||||
CompilationOutcomeDescriptor.forExpectedCompilationResult(
|
CompilationOutcomeDescriptor.forExpectedCompilationResult(
|
||||||
method.getAnnotation( ExpectedCompilationOutcome.class )
|
method.getAnnotation( ExpectedCompilationOutcome.class )
|
||||||
@ -201,7 +165,7 @@ class CompilingStatement extends Statement {
|
|||||||
|
|
||||||
if ( expectedResult.getCompilationResult() == CompilationResult.SUCCEEDED ) {
|
if ( expectedResult.getCompilationResult() == CompilationResult.SUCCEEDED ) {
|
||||||
assertThat( actualResult.getCompilationResult() ).describedAs(
|
assertThat( actualResult.getCompilationResult() ).describedAs(
|
||||||
"Compilation failed. Diagnostics: " + compilationResult.diagnostics.getDiagnostics()
|
"Compilation failed. Diagnostics: " + actualResult.getDiagnostics()
|
||||||
).isEqualTo(
|
).isEqualTo(
|
||||||
CompilationResult.SUCCEEDED
|
CompilationResult.SUCCEEDED
|
||||||
);
|
);
|
||||||
@ -263,6 +227,7 @@ class CompilingStatement extends Statement {
|
|||||||
|
|
||||||
Collections.sort( actualDiagnostics, COMPARATOR );
|
Collections.sort( actualDiagnostics, COMPARATOR );
|
||||||
Collections.sort( expectedDiagnostics, COMPARATOR );
|
Collections.sort( expectedDiagnostics, COMPARATOR );
|
||||||
|
expectedDiagnostics = filterExpectedDiagnostics( expectedDiagnostics );
|
||||||
|
|
||||||
Iterator<DiagnosticDescriptor> actualIterator = actualDiagnostics.iterator();
|
Iterator<DiagnosticDescriptor> actualIterator = actualDiagnostics.iterator();
|
||||||
Iterator<DiagnosticDescriptor> expectedIterator = expectedDiagnostics.iterator();
|
Iterator<DiagnosticDescriptor> expectedIterator = expectedDiagnostics.iterator();
|
||||||
@ -299,10 +264,18 @@ class CompilingStatement extends Statement {
|
|||||||
actual.getLine(),
|
actual.getLine(),
|
||||||
actual.getKind()
|
actual.getKind()
|
||||||
)
|
)
|
||||||
).matches( ".*" + expected.getMessage() + ".*" );
|
).matches( "(?ms).*" + expected.getMessage() + ".*" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param expectedDiagnostics expected diagnostics
|
||||||
|
* @return a possibly filtered list of expected diagnostics
|
||||||
|
*/
|
||||||
|
protected List<DiagnosticDescriptor> filterExpectedDiagnostics(List<DiagnosticDescriptor> expectedDiagnostics) {
|
||||||
|
return expectedDiagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the classes to be compiled for this test.
|
* Returns the classes to be compiled for this test.
|
||||||
*
|
*
|
||||||
@ -371,7 +344,7 @@ class CompilingStatement extends Statement {
|
|||||||
return String.format( "-A%s=%s", processorOption.name(), processorOption.value() );
|
return String.format( "-A%s=%s", processorOption.name(), processorOption.value() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<File> getSourceFiles(Collection<Class<?>> classes) {
|
protected Set<File> getSourceFiles(Collection<Class<?>> classes) {
|
||||||
Set<File> sourceFiles = new HashSet<File>( classes.size() );
|
Set<File> sourceFiles = new HashSet<File>( classes.size() );
|
||||||
|
|
||||||
for ( Class<?> clazz : classes ) {
|
for ( Class<?> clazz : classes ) {
|
||||||
@ -386,52 +359,30 @@ class CompilingStatement extends Statement {
|
|||||||
return sourceFiles;
|
return sourceFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompilationResultHolder compile()
|
private CompilationOutcomeDescriptor compile()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
CompilationCache cache = COMPILATION_CACHE.get();
|
|
||||||
if ( !needsRecompilation() ) {
|
if ( !needsRecompilation() ) {
|
||||||
return cache.lastResult;
|
return compilationCache.getLastResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
setupCompiler();
|
setupDirectories();
|
||||||
cache.lastSourceOutputDir = sourceOutputDir;
|
compilationCache.setLastSourceOutputDir( sourceOutputDir );
|
||||||
|
|
||||||
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
|
CompilationOutcomeDescriptor resultHolder =
|
||||||
StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );
|
compileWithSpecificCompiler( compilationRequest, sourceOutputDir, classOutputDir );
|
||||||
|
|
||||||
Iterable<? extends JavaFileObject> compilationUnits =
|
compilationCache.update( compilationRequest, resultHolder );
|
||||||
fileManager.getJavaFileObjectsFromFiles( getSourceFiles( compilationRequest.sourceClasses ) );
|
|
||||||
|
|
||||||
try {
|
|
||||||
fileManager.setLocation( StandardLocation.CLASS_PATH, COMPILER_CLASSPATH );
|
|
||||||
fileManager.setLocation( StandardLocation.CLASS_OUTPUT, Arrays.asList( new File( classOutputDir ) ) );
|
|
||||||
fileManager.setLocation( StandardLocation.SOURCE_OUTPUT, Arrays.asList( new File( sourceOutputDir ) ) );
|
|
||||||
}
|
|
||||||
catch ( IOException e ) {
|
|
||||||
throw new RuntimeException( e );
|
|
||||||
}
|
|
||||||
|
|
||||||
CompilationTask task =
|
|
||||||
compiler.getTask(
|
|
||||||
null,
|
|
||||||
fileManager,
|
|
||||||
diagnostics,
|
|
||||||
compilationRequest.processorOptions,
|
|
||||||
null,
|
|
||||||
compilationUnits );
|
|
||||||
|
|
||||||
task.setProcessors( Arrays.asList( new MappingProcessor() ) );
|
|
||||||
|
|
||||||
CompilationResultHolder resultHolder = new CompilationResultHolder( diagnostics, task.call() );
|
|
||||||
|
|
||||||
cache.lastRequest = compilationRequest;
|
|
||||||
cache.lastResult = resultHolder;
|
|
||||||
return resultHolder;
|
return resultHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean needsRecompilation() {
|
protected abstract CompilationOutcomeDescriptor compileWithSpecificCompiler(
|
||||||
return !compilationRequest.equals( COMPILATION_CACHE.get().lastRequest );
|
CompilationRequest compilationRequest,
|
||||||
|
String sourceOutputDir,
|
||||||
|
String classOutputDir);
|
||||||
|
|
||||||
|
boolean needsRecompilation() {
|
||||||
|
return !compilationRequest.equals( compilationCache.getLastRequest() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getBasePath() {
|
private static String getBasePath() {
|
||||||
@ -485,66 +436,7 @@ class CompilingStatement extends Statement {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using the message is not perfect when using regular expressions,
|
return o1.getKind().compareTo( o2.getKind() );
|
||||||
// but it's better than nothing
|
|
||||||
return o1.getMessage().compareTo( o2.getMessage() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CompilationCache {
|
|
||||||
private String lastSourceOutputDir;
|
|
||||||
private CompilationRequest lastRequest;
|
|
||||||
private CompilationResultHolder lastResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the result of a compilation.
|
|
||||||
*/
|
|
||||||
private static class CompilationResultHolder {
|
|
||||||
private final DiagnosticCollector<JavaFileObject> diagnostics;
|
|
||||||
private final boolean compilationSuccessful;
|
|
||||||
|
|
||||||
public CompilationResultHolder(DiagnosticCollector<JavaFileObject> diagnostics, boolean compilationSuccessful) {
|
|
||||||
this.diagnostics = diagnostics;
|
|
||||||
this.compilationSuccessful = compilationSuccessful;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a compilation task for a number of sources with given processor options.
|
|
||||||
*/
|
|
||||||
private static class CompilationRequest {
|
|
||||||
private final Set<Class<?>> sourceClasses;
|
|
||||||
private final List<String> processorOptions;
|
|
||||||
|
|
||||||
public CompilationRequest(Set<Class<?>> sourceClasses, List<String> processorOptions) {
|
|
||||||
this.sourceClasses = sourceClasses;
|
|
||||||
this.processorOptions = processorOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + ( ( processorOptions == null ) ? 0 : processorOptions.hashCode() );
|
|
||||||
result = prime * result + ( ( sourceClasses == null ) ? 0 : sourceClasses.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;
|
|
||||||
}
|
|
||||||
CompilationRequest other = (CompilationRequest) obj;
|
|
||||||
|
|
||||||
return processorOptions.equals( other.processorOptions ) && sourceClasses.equals( other.sourceClasses );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* 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.runner;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.codehaus.plexus.compiler.CompilerConfiguration;
|
||||||
|
import org.codehaus.plexus.compiler.CompilerException;
|
||||||
|
import org.codehaus.plexus.compiler.CompilerResult;
|
||||||
|
import org.codehaus.plexus.logging.console.ConsoleLogger;
|
||||||
|
import org.eclipse.tycho.compiler.jdt.JDTCompiler;
|
||||||
|
import org.junit.runners.model.FrameworkMethod;
|
||||||
|
import org.mapstruct.ap.MappingProcessor;
|
||||||
|
import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statement that uses the JDK compiler to compile.
|
||||||
|
*
|
||||||
|
* @author Andreas Gudian
|
||||||
|
*/
|
||||||
|
class EclipseCompilingStatement extends CompilingStatement {
|
||||||
|
|
||||||
|
EclipseCompilingStatement(FrameworkMethod method, CompilationCache compilationCache) {
|
||||||
|
super( method, compilationCache );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CompilationOutcomeDescriptor compileWithSpecificCompiler(CompilationRequest compilationRequest,
|
||||||
|
String sourceOutputDir,
|
||||||
|
String classOutputDir) {
|
||||||
|
JDTCompiler compiler = new JDTCompiler();
|
||||||
|
compiler.enableLogging( new ConsoleLogger( 5, "JDT-Compiler" ) );
|
||||||
|
|
||||||
|
CompilerConfiguration config = new CompilerConfiguration();
|
||||||
|
|
||||||
|
config.setClasspathEntries( COMPILER_CLASSPATH );
|
||||||
|
config.setOutputLocation( classOutputDir );
|
||||||
|
config.setGeneratedSourcesDirectory( new File( sourceOutputDir ) );
|
||||||
|
config.setAnnotationProcessors( new String[] { MappingProcessor.class.getName() } );
|
||||||
|
config.setSourceFiles( getSourceFiles( compilationRequest.getSourceClasses() ) );
|
||||||
|
config.setShowWarnings( false );
|
||||||
|
config.setSourceVersion( "1.6" );
|
||||||
|
config.setTargetVersion( "1.6" );
|
||||||
|
|
||||||
|
for ( String option : compilationRequest.getProcessorOptions() ) {
|
||||||
|
config.addCompilerCustomArgument( option, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilerResult compilerResult;
|
||||||
|
try {
|
||||||
|
compilerResult = compiler.performCompile( config );
|
||||||
|
}
|
||||||
|
catch ( CompilerException e ) {
|
||||||
|
throw new RuntimeException( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompilationOutcomeDescriptor.forResult(
|
||||||
|
SOURCE_DIR,
|
||||||
|
compilerResult );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPathSuffix() {
|
||||||
|
return "_eclipse";
|
||||||
|
}
|
||||||
|
}
|
@ -39,11 +39,21 @@ import org.mapstruct.ap.testutil.assertions.JavaFileAssert;
|
|||||||
*/
|
*/
|
||||||
public class GeneratedSource implements TestRule {
|
public class GeneratedSource implements TestRule {
|
||||||
|
|
||||||
|
private static ThreadLocal<CompilingStatement> compilingStatement = new ThreadLocal<CompilingStatement>();;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Statement apply(Statement base, Description description) {
|
public Statement apply(Statement base, Description description) {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setCompilingStatement(CompilingStatement compilingStatement) {
|
||||||
|
GeneratedSource.compilingStatement.set( compilingStatement );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clearCompilingStatement() {
|
||||||
|
GeneratedSource.compilingStatement.remove();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mapperClass the class annotated with {@code @Mapper}
|
* @param mapperClass the class annotated with {@code @Mapper}
|
||||||
*
|
*
|
||||||
@ -60,6 +70,6 @@ public class GeneratedSource implements TestRule {
|
|||||||
* @return an assert for the file specified by the given path
|
* @return an assert for the file specified by the given path
|
||||||
*/
|
*/
|
||||||
public JavaFileAssert forJavaFile(String path) {
|
public JavaFileAssert forJavaFile(String path) {
|
||||||
return new JavaFileAssert( new File( CompilingStatement.getSourceOutputDir() + "/" + path ) );
|
return new JavaFileAssert( new File( compilingStatement.get().getSourceOutputDir() + "/" + path ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,150 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* 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.runner;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||||
|
import org.junit.runners.model.FrameworkMethod;
|
||||||
|
import org.junit.runners.model.Statement;
|
||||||
|
import org.junit.runners.model.TestClass;
|
||||||
|
import org.mapstruct.ap.testutil.WithClasses;
|
||||||
|
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
|
||||||
|
import org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JUnit4 runner for Annotation Processor tests.
|
||||||
|
* <p>
|
||||||
|
* Test classes and test methods are safe to be executed in parallel.
|
||||||
|
* <p>
|
||||||
|
* The classes to be compiled for a given test method must be specified via {@link WithClasses}. In addition the
|
||||||
|
* following things can be configured optionally :
|
||||||
|
* <ul>
|
||||||
|
* <li>Processor options to be considered during compilation via {@link ProcessorOption}.</li>
|
||||||
|
* <li>The expected compilation outcome and expected diagnostics can be specified via {@link ExpectedCompilationOutcome}
|
||||||
|
* . If no outcome is specified, a successful compilation is assumed.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author Gunnar Morling
|
||||||
|
* @author Andreas Gudian
|
||||||
|
*/
|
||||||
|
class InnerAnnotationProcessorRunner extends BlockJUnit4ClassRunner {
|
||||||
|
static final ModifiableURLClassLoader TEST_CLASS_LOADER = new ModifiableURLClassLoader();
|
||||||
|
private final Class<?> klass;
|
||||||
|
private final Compiler compiler;
|
||||||
|
private final CompilationCache compilationCache;
|
||||||
|
private Class<?> klassToUse;
|
||||||
|
private ReplacableTestClass replacableTestClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param klass the test class
|
||||||
|
*
|
||||||
|
* @throws Exception see {@link BlockJUnit4ClassRunner#BlockJUnit4ClassRunner(Class)}
|
||||||
|
*/
|
||||||
|
InnerAnnotationProcessorRunner(Class<?> klass, Compiler compiler) throws Exception {
|
||||||
|
super( klass );
|
||||||
|
this.klass = klass;
|
||||||
|
this.compiler = compiler;
|
||||||
|
this.compilationCache = new CompilationCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* newly loads the class with the test class loader and sets that loader as context class loader of the thread
|
||||||
|
*
|
||||||
|
* @param klass the class to replace
|
||||||
|
*
|
||||||
|
* @return the class loaded with the test class loader
|
||||||
|
*/
|
||||||
|
private static Class<?> replaceClassLoaderAndClass(Class<?> klass) {
|
||||||
|
replaceContextClassLoader( klass );
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Thread.currentThread().getContextClassLoader().loadClass( klass.getName() );
|
||||||
|
}
|
||||||
|
catch ( ClassNotFoundException e ) {
|
||||||
|
throw new RuntimeException( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void replaceContextClassLoader(Class<?> klass) {
|
||||||
|
String classFileName = klass.getName().replace( ".", "/" ) + ".class";
|
||||||
|
URL classResource = klass.getClassLoader().getResource( classFileName );
|
||||||
|
String fullyQualifiedUrl = classResource.toExternalForm();
|
||||||
|
String basePath = fullyQualifiedUrl.substring( 0, fullyQualifiedUrl.length() - classFileName.length() );
|
||||||
|
|
||||||
|
ModifiableURLClassLoader testClassLoader = new ModifiableURLClassLoader();
|
||||||
|
testClassLoader.addURL( basePath );
|
||||||
|
|
||||||
|
Thread.currentThread().setContextClassLoader( testClassLoader );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TestClass createTestClass(final Class<?> testClass) {
|
||||||
|
replacableTestClass = new ReplacableTestClass( testClass );
|
||||||
|
return replacableTestClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FrameworkMethod replaceFrameworkMethod(FrameworkMethod m) {
|
||||||
|
try {
|
||||||
|
return new FrameworkMethod(
|
||||||
|
klassToUse.getDeclaredMethod( m.getName(), m.getMethod().getParameterTypes() ) );
|
||||||
|
}
|
||||||
|
catch ( NoSuchMethodException e ) {
|
||||||
|
throw new RuntimeException( e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Statement methodBlock(FrameworkMethod method) {
|
||||||
|
CompilingStatement statement = createCompilingStatement( method );
|
||||||
|
if ( statement.needsRecompilation() ) {
|
||||||
|
klassToUse = replaceClassLoaderAndClass( klass );
|
||||||
|
|
||||||
|
replacableTestClass.replaceClass( klassToUse );
|
||||||
|
}
|
||||||
|
|
||||||
|
method = replaceFrameworkMethod( method );
|
||||||
|
|
||||||
|
Statement next = super.methodBlock( method );
|
||||||
|
|
||||||
|
statement.setNextStatement( next );
|
||||||
|
|
||||||
|
return statement;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompilingStatement createCompilingStatement(FrameworkMethod method) {
|
||||||
|
if ( compiler == Compiler.JDK ) {
|
||||||
|
return new JdkCompilingStatement( method, compilationCache );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new EclipseCompilingStatement( method, compilationCache );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getName() {
|
||||||
|
return "[" + compiler.name().toLowerCase() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String testName(FrameworkMethod method) {
|
||||||
|
return method.getName() + getName();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* 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.runner;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
import javax.tools.DiagnosticCollector;
|
||||||
|
import javax.tools.JavaCompiler;
|
||||||
|
import javax.tools.JavaCompiler.CompilationTask;
|
||||||
|
import javax.tools.JavaFileObject;
|
||||||
|
import javax.tools.StandardJavaFileManager;
|
||||||
|
import javax.tools.StandardLocation;
|
||||||
|
import javax.tools.ToolProvider;
|
||||||
|
|
||||||
|
import org.junit.runners.model.FrameworkMethod;
|
||||||
|
import org.mapstruct.ap.MappingProcessor;
|
||||||
|
import org.mapstruct.ap.testutil.compilation.model.CompilationOutcomeDescriptor;
|
||||||
|
import org.mapstruct.ap.testutil.compilation.model.DiagnosticDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Statement that uses the JDK compiler to compile.
|
||||||
|
*
|
||||||
|
* @author Andreas Gudian
|
||||||
|
*/
|
||||||
|
class JdkCompilingStatement extends CompilingStatement {
|
||||||
|
|
||||||
|
private static final List<File> COMPILER_CLASSPATH_FILES = asFiles( COMPILER_CLASSPATH );
|
||||||
|
|
||||||
|
JdkCompilingStatement(FrameworkMethod method, CompilationCache compilationCache) {
|
||||||
|
super( method, compilationCache );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CompilationOutcomeDescriptor compileWithSpecificCompiler(CompilationRequest compilationRequest,
|
||||||
|
String sourceOutputDir,
|
||||||
|
String classOutputDir) {
|
||||||
|
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||||
|
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
|
||||||
|
StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );
|
||||||
|
|
||||||
|
Iterable<? extends JavaFileObject> compilationUnits =
|
||||||
|
fileManager.getJavaFileObjectsFromFiles( getSourceFiles( compilationRequest.getSourceClasses() ) );
|
||||||
|
|
||||||
|
try {
|
||||||
|
fileManager.setLocation( StandardLocation.CLASS_PATH, COMPILER_CLASSPATH_FILES );
|
||||||
|
fileManager.setLocation( StandardLocation.CLASS_OUTPUT, Arrays.asList( new File( classOutputDir ) ) );
|
||||||
|
fileManager.setLocation( StandardLocation.SOURCE_OUTPUT, Arrays.asList( new File( sourceOutputDir ) ) );
|
||||||
|
}
|
||||||
|
catch ( IOException e ) {
|
||||||
|
throw new RuntimeException( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilationTask task =
|
||||||
|
compiler.getTask(
|
||||||
|
null,
|
||||||
|
fileManager,
|
||||||
|
diagnostics,
|
||||||
|
compilationRequest.getProcessorOptions(),
|
||||||
|
null,
|
||||||
|
compilationUnits );
|
||||||
|
|
||||||
|
task.setProcessors( Arrays.asList( new MappingProcessor() ) );
|
||||||
|
|
||||||
|
Boolean compilationSuccessful = task.call();
|
||||||
|
|
||||||
|
return CompilationOutcomeDescriptor.forResult(
|
||||||
|
SOURCE_DIR,
|
||||||
|
compilationSuccessful,
|
||||||
|
diagnostics.getDiagnostics() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<File> asFiles(List<String> paths) {
|
||||||
|
List<File> classpath = new ArrayList<File>();
|
||||||
|
for ( String path : paths ) {
|
||||||
|
classpath.add( new File( path ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return classpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JDK compiler only reports the first message of kind ERROR that is reported for one source file line, so we
|
||||||
|
* filter out the surplus diagnostics. The input list is already sorted by file name and line number, with the order
|
||||||
|
* for the diagnostics in the same line being kept at the order as given in the test.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected List<DiagnosticDescriptor> filterExpectedDiagnostics(List<DiagnosticDescriptor> expectedDiagnostics) {
|
||||||
|
List<DiagnosticDescriptor> filtered = new ArrayList<DiagnosticDescriptor>( expectedDiagnostics.size() );
|
||||||
|
|
||||||
|
DiagnosticDescriptor previous = null;
|
||||||
|
for ( DiagnosticDescriptor diag : expectedDiagnostics ) {
|
||||||
|
if ( diag.getKind() != Kind.ERROR
|
||||||
|
|| previous == null
|
||||||
|
|| !previous.getSourceFileName().equals( diag.getSourceFileName() )
|
||||||
|
|| !previous.getLine().equals( diag.getLine() ) ) {
|
||||||
|
filtered.add( diag );
|
||||||
|
previous = diag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPathSuffix() {
|
||||||
|
return "_jdk";
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user