#1308 Switch to JUnit Jupiter and do not use Toolchains for the integration tests (#2013)

The CI should be setup to run on different Java versions, for which the integration tests are going to be run
This commit is contained in:
Filip Hrisafov 2020-02-03 21:56:48 +01:00 committed by GitHub
parent 95ceba1a1e
commit 02a113b2d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 773 additions and 1130 deletions

View File

@ -1,6 +1,6 @@
language: java
install: true
script: mvn clean install -DprocessorIntegrationTest.toolchainsFile=etc/toolchains-travis-jenkins.xml -B -V
script: mvn clean install -B -V
matrix:
include:
@ -9,20 +9,14 @@ matrix:
- mvn jacoco:report && bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"
dist: trusty
- jdk: openjdk11
# Only run the processor and its dependencies
# The integration tests are using the maven toolchain and that is not yet ready for Java 11
# There is an issue with the documentation so skip it
script: mvn -B -V clean install -pl processor -am
script: mvn -B -V clean install -DskipDistribution=true
- jdk: openjdk13
# Only run the processor and its dependencies
# The integration tests are using the maven toolchain and that is not yet ready for Java 11
# There is an issue with the documentation so skip it
script: mvn -B -V clean install -pl processor -am
# Only run the processor and its dependencies
# The integration tests are using the maven toolchain and that is not yet ready for Java EA
script: mvn -B -V clean install -DskipDistribution=true
# There is an issue with the documentation so skip it
- jdk: openjdk-ea
script: mvn -B -V clean install -pl processor -am
script: mvn -B -V clean install -DskipDistribution=true
allow_failures:
- jdk: openjdk-ea
deploy:

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.8</version>
<vendor>oracle</vendor>
<id>jdk1.8</id>
</provides>
<configuration>
<jdkHome>/opt/jdk/jdk8.latest</jdkHome>
</configuration>
</toolchain>
</toolchains>

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.8.0_11</version>
<vendor>oracle</vendor>
<id>jdk1.8</id>
</provides>
<configuration>
<jdkHome>C:\Program Files\Java\jdk1.8.0_11</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<version>1.9.0</version>
<vendor>oracle</vendor>
<id>jdk1.9</id>
</provides>
<configuration>
<jdkHome>C:\Program Files\Java\jdk1.9.0</jdkHome>
</configuration>
</toolchain>
</toolchains>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<version>1.8</version>
<vendor>oracle</vendor>
<id>jdk1.8</id>
</provides>
<configuration>
<jdkHome>/usr/lib/jvm/java-8-oracle/</jdkHome>
</configuration>
</toolchain>
</toolchains>

View File

@ -40,11 +40,6 @@
<dependencies>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
@ -73,6 +68,17 @@
<version>2.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -1,19 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Filip Hrisafov
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite(baseDir = "autoValueBuilderTest",
processorTypes = ProcessorSuite.ProcessorType.ALL_WITHOUT_PROCESSOR_PLUGIN)
public class AutoValueBuilderTest {
}

View File

@ -1,20 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Andreas Gudian
*
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite( baseDir = "cdiTest", processorTypes = ProcessorType.ALL )
public class CdiTest {
}

View File

@ -1,22 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
*
* See: https://github.com/mapstruct/mapstruct/issues/1121
*
* @author Sjaak Derksen
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite(baseDir = "externalbeanjar", processorTypes = ProcessorSuite.ProcessorType.ORACLE_JAVA_8)
public class ExternalBeanJarTest {
}

View File

@ -1,19 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Filip Hrisafov
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite( baseDir = "freeBuilderBuilderTest",
processorTypes = ProcessorSuite.ProcessorType.ALL_WITHOUT_PROCESSOR_PLUGIN)
public class FreeBuilderBuilderTest {
}

View File

@ -0,0 +1,45 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.jupiter.api.condition.JRE;
import org.mapstruct.itest.testutil.extension.ProcessorTest;
/**
* Adds explicit exclusions of test mappers that are known or expected to not work with specific compilers.
*
* @author Andreas Gudian
*/
public final class FullFeatureCompilationExclusionCliEnhancer implements ProcessorTest.CommandLineEnhancer {
@Override
public Collection<String> getAdditionalCommandLineArguments(ProcessorTest.ProcessorType processorType,
JRE currentJreVersion) {
List<String> additionalExcludes = new ArrayList<>();
// SPI not working correctly here.. (not picked up)
additionalExcludes.add( "org/mapstruct/ap/test/bugs/_1596/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/bugs/_1801/*.java" );
switch ( currentJreVersion ) {
case JAVA_9:
// TODO find out why this fails:
additionalExcludes.add( "org/mapstruct/ap/test/collection/wildcard/BeanMapper.java" );
break;
default:
}
Collection<String> result = new ArrayList<String>( additionalExcludes.size() );
for ( int i = 0; i < additionalExcludes.size(); i++ ) {
result.add( "-DadditionalExclude" + i + "=" + additionalExcludes.get( i ) );
}
return result;
}
}

View File

@ -1,72 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.junit.runner.RunWith;
import org.mapstruct.itest.tests.FullFeatureCompilationTest.CompilationExclusionCliEnhancer;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.CommandLineEnhancer;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* Integration test that compiles all test mappers in the processor-module, excluding all classes that contain one of
* the following in their path/file name:
* <ul>
* <li>{@code /erronerous/}</li>
* <li>{@code *Erroneous*}</li>
* <li>{@code *Test.java}</li>
* <li>{@code /testutil/}</li>
* <li>possibly more, depending on the processor type - see {@link CompilationExclusionCliEnhancer}</li>
* </ul>
*
* @author Andreas Gudian
*/
@RunWith(ProcessorSuiteRunner.class)
@ProcessorSuite(
baseDir = "fullFeatureTest",
commandLineEnhancer = CompilationExclusionCliEnhancer.class,
processorTypes = {
ProcessorType.ORACLE_JAVA_8,
ProcessorType.ORACLE_JAVA_9,
ProcessorType.ECLIPSE_JDT_JAVA_8
})
public class FullFeatureCompilationTest {
/**
* Adds explicit exclusions of test mappers that are known or expected to not work with specific compilers.
*
* @author Andreas Gudian
*/
public static final class CompilationExclusionCliEnhancer implements CommandLineEnhancer {
@Override
public Collection<String> getAdditionalCommandLineArguments(ProcessorType processorType) {
List<String> additionalExcludes = new ArrayList<>();
// SPI not working correctly here.. (not picked up)
additionalExcludes.add( "org/mapstruct/ap/test/bugs/_1596/*.java" );
additionalExcludes.add( "org/mapstruct/ap/test/bugs/_1801/*.java" );
switch ( processorType ) {
case ORACLE_JAVA_9:
// TODO find out why this fails:
additionalExcludes.add( "org/mapstruct/ap/test/collection/wildcard/BeanMapper.java" );
break;
default:
}
Collection<String> result = new ArrayList<String>( additionalExcludes.size() );
for ( int i = 0; i < additionalExcludes.size(); i++ ) {
result.add( "-DadditionalExclude" + i + "=" + additionalExcludes.get( i ) );
}
return result;
}
}
}

View File

@ -5,12 +5,6 @@
*/
package org.mapstruct.itest.tests;
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
import static org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
@ -24,40 +18,40 @@ import org.apache.commons.io.FileUtils;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.runners.Parameterized.Parameters;
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
import static org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* <p>This is supposed to be run from the mapstruct root project folder.
* Otherwise, use <code>-Dmapstruct_root=path_to_project</code>.
*/
@RunWith( Parameterized.class )
@DisabledForJreRange(min = JRE.JAVA_11)
public class GradleIncrementalCompilationTest {
private static Path rootPath;
private static String projectDir = "integrationtest/src/test/resources/gradleIncrementalCompilationTest";
private static String compileTaskName = "compileJava";
@Rule
public final TemporaryFolder testBuildDir = new TemporaryFolder();
@Rule
public final TemporaryFolder testProjectDir = new TemporaryFolder();
@TempDir
File testBuildDir;
@TempDir
File testProjectDir;
private String gradleVersion;
private GradleRunner runner;
private File sourceDirectory;
private List<String> compileArgs; // Gradle compile task arguments
public GradleIncrementalCompilationTest(String gradleVersion) {
this.gradleVersion = gradleVersion;
}
@Parameters( name = "Gradle {0}" )
@Parameters(name = "Gradle {0}")
public static List<String> gradleVersions() {
return Arrays.asList( "5.0", "6.0" );
}
@ -81,49 +75,62 @@ public class GradleIncrementalCompilationTest {
assertCompileOutcome( result, recompiledCount > 0 ? SUCCESS : UP_TO_DATE );
assertThat(
result.getOutput(),
containsString( String.format( "Incremental compilation of %d classes completed", recompiledCount ) ) );
containsString( String.format( "Incremental compilation of %d classes completed", recompiledCount ) )
);
}
private List<String> buildCompileArgs() {
// Make Gradle use the temporary build folder by overriding the buildDir property
String buildDirPropertyArg = "-PbuildDir=" + testBuildDir.getRoot().getAbsolutePath();
String buildDirPropertyArg = "-PbuildDir=" + testBuildDir.getAbsolutePath();
// Inject the path to the folder containing the mapstruct-processor JAR
String jarDirectoryArg = "-PmapstructRootPath=" + rootPath.toString();
return Arrays.asList( compileTaskName, buildDirPropertyArg, jarDirectoryArg );
}
@BeforeClass
@BeforeAll
public static void setupClass() throws Exception {
rootPath = Paths.get( System.getProperty( "mapstruct_root", "." ) ).toAbsolutePath();
}
@Before
public void setup() throws IOException {
// Copy test project files to the temp dir
Path gradleProjectPath = rootPath.resolve( projectDir );
FileUtils.copyDirectory( gradleProjectPath.toFile(), testProjectDir.getRoot() );
compileArgs = buildCompileArgs();
sourceDirectory = new File( testProjectDir.getRoot(), "src/main/java" );
runner = GradleRunner.create().withGradleVersion( gradleVersion ).withProjectDir( testProjectDir.getRoot() );
public void setup(String gradleVersion) throws IOException {
if ( !testBuildDir.exists() ) {
testBuildDir.mkdirs();
}
@Test
public void testBuildSucceeds() throws IOException {
if ( !testProjectDir.exists() ) {
testProjectDir.mkdirs();
}
// Copy test project files to the temp dir
Path gradleProjectPath = rootPath.resolve( projectDir );
FileUtils.copyDirectory( gradleProjectPath.toFile(), testProjectDir );
compileArgs = buildCompileArgs();
sourceDirectory = new File( testProjectDir, "src/main/java" );
runner = GradleRunner.create().withGradleVersion( gradleVersion ).withProjectDir( testProjectDir );
}
@ParameterizedTest
@MethodSource("gradleVersions")
public void testBuildSucceeds(String gradleVersion) throws IOException {
setup( gradleVersion );
// Make sure the test build setup actually compiles
BuildResult buildResult = getRunner().build();
assertCompileOutcome( buildResult, SUCCESS );
}
@Test
public void testUpToDate() throws IOException {
@ParameterizedTest
@MethodSource("gradleVersions")
public void testUpToDate(String gradleVersion) throws IOException {
setup( gradleVersion );
getRunner().build();
BuildResult secondBuildResult = getRunner().build();
assertCompileOutcome( secondBuildResult, UP_TO_DATE );
}
@Test
public void testChangeConstant() throws IOException {
@ParameterizedTest
@MethodSource("gradleVersions")
public void testChangeConstant(String gradleVersion) throws IOException {
setup( gradleVersion );
getRunner().build();
// Change return value in class Target
File targetFile = new File( sourceDirectory, "org/mapstruct/itest/gradle/model/Target.java" );
@ -134,8 +141,10 @@ public class GradleIncrementalCompilationTest {
assertRecompiled( secondBuildResult, 3 );
}
@Test
public void testChangeTargetField() throws IOException {
@ParameterizedTest
@MethodSource("gradleVersions")
public void testChangeTargetField(String gradleVersion) throws IOException {
setup( gradleVersion );
getRunner().build();
// Change target field in mapper interface
File mapperFile = new File( sourceDirectory, "org/mapstruct/itest/gradle/lib/TestMapper.java" );
@ -146,8 +155,10 @@ public class GradleIncrementalCompilationTest {
assertRecompiled( secondBuildResult, 2 );
}
@Test
public void testChangeUnrelatedFile() throws IOException {
@ParameterizedTest
@MethodSource("gradleVersions")
public void testChangeUnrelatedFile(String gradleVersion) throws IOException {
setup( gradleVersion );
getRunner().build();
File unrelatedFile = new File( sourceDirectory, "org/mapstruct/itest/gradle/lib/UnrelatedComponent.java" );
replaceInFile( unrelatedFile, "true", "false" );

View File

@ -1,19 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Filip Hrisafov
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite( baseDir = "immutablesBuilderTest",
processorTypes = ProcessorSuite.ProcessorType.ALL_WITHOUT_PROCESSOR_PLUGIN)
public class ImmutablesBuilderTest {
}

View File

@ -1,20 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Andreas Gudian
*
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite( baseDir = "java8Test", processorTypes = ProcessorType.ALL_JAVA_8 )
public class Java8Test {
}

View File

@ -1,20 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Andreas Gudian
*
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite( baseDir = "jaxbTest", processorTypes = ProcessorType.ALL )
public class JaxbTest {
}

View File

@ -1,20 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Andreas Gudian
*
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite( baseDir = "jsr330Test", processorTypes = ProcessorType.ALL )
public class Jsr330Test {
}

View File

@ -1,23 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Eric Martineau
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite( baseDir = "lombokBuilderTest",
processorTypes = {
ProcessorSuite.ProcessorType.ORACLE_JAVA_8,
ProcessorSuite.ProcessorType.ORACLE_JAVA_9,
}
)
public class LombokBuilderTest {
}

View File

@ -0,0 +1,124 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mapstruct.itest.testutil.extension.ProcessorTest;
/**
* @author Filip Hrisafov
*/
@Execution( ExecutionMode.CONCURRENT )
public class MavenIntegrationTest {
@ProcessorTest(baseDir = "autoValueBuilderTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC,
ProcessorTest.ProcessorType.ECLIPSE_JDT
})
void autoValueBuilderTest() {
}
@ProcessorTest(baseDir = "cdiTest")
void cdiTest() {
}
/**
* See: https://github.com/mapstruct/mapstruct/issues/1121
*/
@ProcessorTest(baseDir = "externalbeanjar", processorTypes = ProcessorTest.ProcessorType.JAVAC)
void externalBeanJarTest() {
}
@ProcessorTest(baseDir = "freeBuilderBuilderTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC,
ProcessorTest.ProcessorType.ECLIPSE_JDT
})
void freeBuilderBuilderTest() {
}
/**
* Integration test that compiles all test mappers in the processor-module, excluding all classes that contain
* one of
* the following in their path/file name:
* <ul>
* <li>{@code /erronerous/}</li>
* <li>{@code *Erroneous*}</li>
* <li>{@code *Test.java}</li>
* <li>{@code /testutil/}</li>
* <li>possibly more, depending on the processor type - see {@link FullFeatureCompilationExclusionCliEnhancer}</li>
* </ul>
*/
@ProcessorTest(baseDir = "fullFeatureTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC,
ProcessorTest.ProcessorType.ECLIPSE_JDT
}, commandLineEnhancer = FullFeatureCompilationExclusionCliEnhancer.class)
void fullFeatureTest() {
}
@ProcessorTest(baseDir = "immutablesBuilderTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC,
ProcessorTest.ProcessorType.ECLIPSE_JDT
})
void immutablesBuilderTest() {
}
@ProcessorTest(baseDir = "java8Test")
void java8Test() {
}
@ProcessorTest(baseDir = "jaxbTest")
void jaxbTest() {
}
@ProcessorTest(baseDir = "jsr330Test")
void jsr330Test() {
}
@ProcessorTest(baseDir = "lombokBuilderTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC
})
void lombokBuilderTest() {
}
@ProcessorTest(baseDir = "namingStrategyTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC
})
void namingStrategyTest() {
}
/**
* ECLIPSE_JDT is not working with Protobuf. Use all other available processor types.
*/
@ProcessorTest(baseDir = "protobufBuilderTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC
})
void protobufBuilderTest() {
}
@ProcessorTest(baseDir = "simpleTest")
void simpleTest() {
}
@ProcessorTest(baseDir = "springTest")
void springTest() {
}
/**
* Tests usage of MapStruct with another processor that generates supertypes of mapping source/target types.
*/
@ProcessorTest(baseDir = "superTypeGenerationTest", processorTypes = ProcessorTest.ProcessorType.JAVAC)
void superTypeGenerationTest() {
}
/**
* Tests usage of MapStruct with another processor that generates the target type of a mapping method.
*/
@ProcessorTest(baseDir = "targetTypeGenerationTest", processorTypes = ProcessorTest.ProcessorType.JAVAC)
void targetTypeGenerationTest() {
}
}

View File

@ -1,20 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Andreas Gudian
*
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite(baseDir = "namingStrategyTest", processorTypes = ProcessorType.ORACLE_JAVA_8)
public class NamingStrategyTest {
}

View File

@ -1,24 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* ECLIPSE_JDT_JAVA_8 is not working with Protobuf. Use all other available processor types.
*
* @author Christian Bandowski
*/
@RunWith(ProcessorSuiteRunner.class)
@ProcessorSuite(baseDir = "protobufBuilderTest",
processorTypes = {
ProcessorSuite.ProcessorType.ORACLE_JAVA_8,
ProcessorSuite.ProcessorType.ORACLE_JAVA_9,
})
public class ProtobufBuilderTest {
}

View File

@ -1,20 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Andreas Gudian
*
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite( baseDir = "simpleTest", processorTypes = ProcessorType.ALL )
public class SimpleTest {
}

View File

@ -1,20 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* @author Andreas Gudian
*
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite( baseDir = "springTest", processorTypes = ProcessorType.ALL )
public class SpringTest {
}

View File

@ -1,21 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* Tests usage of MapStruct with another processor that generates supertypes of mapping source/target types.
*
* @author Gunnar Morling
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite(baseDir = "superTypeGenerationTest", processorTypes = ProcessorType.ORACLE_JAVA_8)
public class SuperTypeGenerationTest {
}

View File

@ -1,21 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.tests;
import org.junit.runner.RunWith;
import org.mapstruct.itest.testutil.runner.ProcessorSuite;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner;
/**
* Tests usage of MapStruct with another processor that generates the target type of a mapping method.
*
* @author Gunnar Morling
*/
@RunWith( ProcessorSuiteRunner.class )
@ProcessorSuite(baseDir = "targetTypeGenerationTest", processorTypes = ProcessorType.ORACLE_JAVA_8)
public class TargetTypeGenerationTest {
}

View File

@ -0,0 +1,37 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.extension;
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtensionContext;
import static org.mapstruct.itest.testutil.extension.ProcessorTestTemplateInvocationContext.CURRENT_VERSION;
/**
* @author Filip Hrisafov
*/
public class ProcessorEnabledOnJreCondition implements ExecutionCondition {
static final ConditionEvaluationResult ENABLED_ON_CURRENT_JRE =
ConditionEvaluationResult.enabled( "Enabled on JRE version: " + System.getProperty( "java.version" ) );
static final ConditionEvaluationResult DISABLED_ON_CURRENT_JRE =
ConditionEvaluationResult.disabled( "Disabled on JRE version: " + System.getProperty( "java.version" ) );
public ProcessorEnabledOnJreCondition(ProcessorTest.ProcessorType processorType) {
this.processorType = processorType;
}
protected final ProcessorTest.ProcessorType processorType;
@Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
// If the max JRE is greater or equal to the current version the test is enabled
return processorType.maxJre().compareTo( CURRENT_VERSION ) >= 0 ? ENABLED_ON_CURRENT_JRE :
DISABLED_ON_CURRENT_JRE;
}
}

View File

@ -0,0 +1,207 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.extension;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.maven.it.Verifier;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.InvocationInterceptor;
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
import org.junit.platform.commons.util.ReflectionUtils;
import static org.apache.maven.it.util.ResourceExtractor.extractResourceToDestination;
import static org.apache.maven.shared.utils.io.FileUtils.copyURLToFile;
import static org.apache.maven.shared.utils.io.FileUtils.deleteDirectory;
import static org.mapstruct.itest.testutil.extension.ProcessorTestTemplateInvocationContext.CURRENT_VERSION;
/**
* @author Filip Hrisafov
* @author Andreas Gudian
*/
public class ProcessorInvocationInterceptor implements InvocationInterceptor {
/**
* System property to enable remote debugging of the processor execution in the integration test
*/
public static final String SYS_PROP_DEBUG = "processorIntegrationTest.debug";
private final ProcessorTestContext processorTestContext;
public ProcessorInvocationInterceptor(ProcessorTestContext processorTestContext) {
this.processorTestContext = processorTestContext;
}
@Override
public void interceptTestTemplateMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
try {
doExecute( extensionContext );
invocation.proceed();
}
catch ( Exception e ) {
invocation.skip();
throw e;
}
}
private void doExecute(ExtensionContext extensionContext) throws Exception {
File destination = extractTest( extensionContext );
PrintStream originalOut = System.out;
final Verifier verifier;
if ( Boolean.getBoolean( SYS_PROP_DEBUG ) ) {
// the compiler is executed within the Maven JVM. So make
// sure we fork a new JVM for that, and let that new JVM use the command 'mvnDebug' instead of 'mvn'
verifier = new Verifier( destination.getCanonicalPath(), null, true, true );
verifier.setDebugJvm( true );
}
else {
verifier = new Verifier( destination.getCanonicalPath() );
}
List<String> goals = new ArrayList<>( 3 );
goals.add( "clean" );
try {
configureProcessor( verifier );
verifier.addCliOption( "-Dcompiler-source-target-version=" + sourceTargetVersion() );
if ( Boolean.getBoolean( SYS_PROP_DEBUG ) ) {
originalOut.print( "Processor Integration Test: " );
originalOut.println( "Listening for transport dt_socket at address: 8000 (in some seconds)" );
}
goals.add( "test" );
addAdditionalCliArguments( verifier );
originalOut.println( extensionContext.getRequiredTestClass().getSimpleName() + "." +
extensionContext.getRequiredTestMethod().getName() + " executing " +
processorTestContext.getProcessor().name().toLowerCase() );
verifier.executeGoals( goals );
verifier.verifyErrorFreeLog();
}
finally {
verifier.resetStreams();
}
}
private void addAdditionalCliArguments(Verifier verifier)
throws Exception {
Class<? extends ProcessorTest.CommandLineEnhancer> cliEnhancerClass =
processorTestContext.getCliEnhancerClass();
Constructor<? extends ProcessorTest.CommandLineEnhancer> cliEnhancerConstructor = null;
if ( cliEnhancerClass != ProcessorTest.CommandLineEnhancer.class ) {
try {
cliEnhancerConstructor = cliEnhancerClass.getConstructor();
ProcessorTest.CommandLineEnhancer enhancer = cliEnhancerConstructor.newInstance();
Collection<String> additionalArgs = enhancer.getAdditionalCommandLineArguments(
processorTestContext.getProcessor(), CURRENT_VERSION );
for ( String arg : additionalArgs ) {
verifier.addCliOption( arg );
}
}
catch ( NoSuchMethodException e ) {
throw new RuntimeException( cliEnhancerClass + " does not have a default constructor." );
}
catch ( SecurityException e ) {
throw new RuntimeException( e );
}
}
}
private void configureProcessor(Verifier verifier) {
String compilerId = processorTestContext.getProcessor().getCompilerId();
if ( compilerId != null ) {
verifier.addCliOption( "-Pgenerate-via-compiler-plugin" );
verifier.addCliOption( "-Dcompiler-id=" + compilerId );
}
else {
verifier.addCliOption( "-Pgenerate-via-processor-plugin" );
}
}
private File extractTest(ExtensionContext extensionContext) throws IOException {
String tmpDir = getTmpDir();
String tempDirName = extensionContext.getRequiredTestClass().getPackage().getName() + "." +
extensionContext.getRequiredTestMethod().getName();
File tempDirBase = new File( tmpDir, tempDirName ).getCanonicalFile();
if ( !tempDirBase.exists() ) {
tempDirBase.mkdirs();
}
File parentPom = new File( tempDirBase, "pom.xml" );
copyURLToFile( getClass().getResource( "/pom.xml" ), parentPom );
ProcessorTest.ProcessorType processorType = processorTestContext.getProcessor();
File tempDir = new File( tempDirBase, processorType.name().toLowerCase() );
deleteDirectory( tempDir );
return extractResourceToDestination( getClass(), "/" + processorTestContext.getBaseDir(), tempDir, true );
}
private String getTmpDir() {
if ( CURRENT_VERSION == JRE.JAVA_8 ) {
// On Java 8 the tmp dir is always
// no matter we run from the aggregator or not
return "target/tmp";
}
// On Java 11+ we need to do it base on the location relative
String tmpDir;
if ( Files.exists( Paths.get( "integrationtest" ) ) ) {
// If it exists then we are running from the main aggregator
tmpDir = "integrationtest/target/tmp";
}
else {
tmpDir = "target/tmp";
}
return tmpDir;
}
private String sourceTargetVersion() {
if ( CURRENT_VERSION == JRE.JAVA_8 ) {
return "1.8";
}
else if ( CURRENT_VERSION == JRE.OTHER ) {
try {
// java.lang.Runtime.version() is a static method available on Java 9+
// that returns an instance of java.lang.Runtime.Version which has the
// following method: public int major()
Method versionMethod = null;
versionMethod = Runtime.class.getMethod( "version" );
Object version = ReflectionUtils.invokeMethod( versionMethod, null );
Method majorMethod = version.getClass().getMethod( "major" );
return String.valueOf( (int) ReflectionUtils.invokeMethod( majorMethod, version ) );
}
catch ( NoSuchMethodException e ) {
throw new RuntimeException( "Failed to get Java Version" );
}
}
else {
return CURRENT_VERSION.name().substring( 5 );
}
}
}

View File

@ -0,0 +1,109 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.extension;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collection;
import org.apache.maven.it.Verifier;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.extension.ExtendWith;
/**
* Declares the content of the integration test.
* <p />
* {@link #baseDir()} must be a path in the classpath that contains the maven module to run as integration test. The
* integration test module should contain at least one test class. The integration test passes, if
* {@code mvn clean test} finishes successfully.
* <p />
* {@link #processorTypes()} configures the variants to execute the integration tests with. See
* {@link ProcessorType}.
*
* @author Filip Hrisafov
*/
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@TestTemplate
@ExtendWith(ProcessorTestTemplateInvocationContextProvider.class)
public @interface ProcessorTest {
/**
* Describes the type of the processing variant(s) to use when executing the integration test.
*
* @author Filip Hrisafov
*/
enum ProcessorType {
JAVAC( "javac" ),
ECLIPSE_JDT( "jdt", JRE.JAVA_8 ),
PROCESSOR_PLUGIN( null, JRE.JAVA_8 );
private final String compilerId;
private final JRE max;
ProcessorType(String compilerId) {
this( compilerId, JRE.OTHER );
}
ProcessorType(String compilerId, JRE max) {
this.compilerId = compilerId;
this.max = max;
}
public String getCompilerId() {
return compilerId;
}
public JRE maxJre() {
return max;
}
}
/**
* Can be configured to provide additional command line arguments for the invoked Maven process, depending on the
* {@link ProcessorType} the test is executed for.
*
* @author Andreas Gudian
*/
interface CommandLineEnhancer {
/**
* @param processorType the processor type for which the test is executed.
* @param currentJreVersion the current JRE version
*
* @return additional command line arguments to be passed to the Maven {@link Verifier}.
*/
Collection<String> getAdditionalCommandLineArguments(ProcessorType processorType,
JRE currentJreVersion);
}
/**
* @return a path in the classpath that contains the maven module to run as integration test: {@code mvn clean test}
*/
String baseDir();
/**
* @return the variants to execute the integration tests with. See {@link ProcessorType}.
*/
ProcessorType[] processorTypes() default {
ProcessorType.JAVAC,
ProcessorType.ECLIPSE_JDT,
ProcessorType.PROCESSOR_PLUGIN
};
/**
* @return the {@link CommandLineEnhancer} implementation. Must have a default constructor.
*/
Class<? extends CommandLineEnhancer> commandLineEnhancer() default CommandLineEnhancer.class;
}

View File

@ -0,0 +1,36 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.extension;
/**
* @author Filip Hrisafov
*/
public class ProcessorTestContext {
private final String baseDir;
private final ProcessorTest.ProcessorType processor;
private final Class<? extends ProcessorTest.CommandLineEnhancer> cliEnhancerClass;
public ProcessorTestContext(String baseDir,
ProcessorTest.ProcessorType processor,
Class<? extends ProcessorTest.CommandLineEnhancer> cliEnhancerClass) {
this.baseDir = baseDir;
this.processor = processor;
this.cliEnhancerClass = cliEnhancerClass;
}
public String getBaseDir() {
return baseDir;
}
public ProcessorTest.ProcessorType getProcessor() {
return processor;
}
public Class<? extends ProcessorTest.CommandLineEnhancer> getCliEnhancerClass() {
return cliEnhancerClass;
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.extension;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.extension.Extension;
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
/**
* @author Filip Hrisafov
*/
public class ProcessorTestTemplateInvocationContext implements TestTemplateInvocationContext {
static final JRE CURRENT_VERSION;
static {
JRE currentVersion = JRE.OTHER;
for ( JRE jre : JRE.values() ) {
if ( jre.isCurrentVersion() ) {
currentVersion = jre;
break;
}
}
CURRENT_VERSION = currentVersion;
}
private final ProcessorTestContext processorTestContext;
public ProcessorTestTemplateInvocationContext(ProcessorTestContext processorTestContext) {
this.processorTestContext = processorTestContext;
}
@Override
public String getDisplayName(int invocationIndex) {
return processorTestContext.getProcessor().name().toLowerCase();
}
@Override
public List<Extension> getAdditionalExtensions() {
List<Extension> extensions = new ArrayList<>();
extensions.add( new ProcessorEnabledOnJreCondition( processorTestContext.getProcessor() ) );
extensions.add( new ProcessorInvocationInterceptor( processorTestContext ) );
return extensions;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.extension;
import java.lang.reflect.Method;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider;
import org.junit.platform.commons.support.AnnotationSupport;
/**
* @author Filip Hrisafov
*/
public class ProcessorTestTemplateInvocationContextProvider implements TestTemplateInvocationContextProvider {
@Override
public boolean supportsTestTemplate(ExtensionContext context) {
return AnnotationSupport.isAnnotated( context.getTestMethod(), ProcessorTest.class );
}
@Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {
Method testMethod = context.getRequiredTestMethod();
ProcessorTest processorTest = AnnotationSupport.findAnnotation( testMethod, ProcessorTest.class )
.orElseThrow( () -> new RuntimeException( "Failed to get ProcessorTest on " + testMethod ) );
return Stream.of( processorTest.processorTypes() )
.map( processorType -> new ProcessorTestTemplateInvocationContext( new ProcessorTestContext(
processorTest.baseDir(),
processorType,
processorTest.commandLineEnhancer()
) ) );
}
}

View File

@ -1,153 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.runner;
import org.apache.maven.it.Verifier;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collection;
/**
* Declares the content of the integration test.
* <p />
* {@link #baseDir()} must be a path in the classpath that contains the maven module to run as integration test. The
* integration test module should contain at least one test class. The integration test passes, if
* {@code mvn clean test} finishes successfully.
* <p />
* {@link #processorTypes()} configures the variants to execute the integration tests with. See {@link ProcessorType}.
*
* @author Andreas Gudian
*/
@Retention( RetentionPolicy.RUNTIME )
@Documented
@Target( ElementType.TYPE )
public @interface ProcessorSuite {
/**
* Describes the type of the processing variant(s) to use when executing the integration test.
* <p />
* Types that require <a href="http://maven.apache.org/guides/mini/guide-using-toolchains.html">toolchains</a>, will
* need the toolchains.xml file to be either installed in ~/m2, or alternatively passed to the mvn process using
* {@code mvn -DprocessorIntegrationTest.toolchainsFile=/path/to/toolchains.xml ...}
*
* @author Andreas Gudian
*/
enum ProcessorType {
/**
* Use the same JDK that runs the mvn build to perform the processing
*/
ORACLE_JAVA_8( null, "javac", "1.8" ),
/**
* Use an Oracle JDK 1.9 (or 1.9.x) via toolchain support to perform the processing
*/
ORACLE_JAVA_9( new Toolchain( "oracle", "9", "10" ), "javac", "1.9" ),
/**
* Use the eclipse compiler with 1.8 source/target level from tycho-compiler-jdt to perform the build and
* processing
*/
ECLIPSE_JDT_JAVA_8( null, "jdt", "1.8" ),
/**
* Use the maven-processor-plugin with 1.8 source/target level with the same JDK that runs the mvn build to
* perform the processing
*/
PROCESSOR_PLUGIN_JAVA_8( null, null, "1.8" ),
/**
* Use all processing variants, but without the maven-procesor-plugin
*/
ALL_WITHOUT_PROCESSOR_PLUGIN( ORACLE_JAVA_8, ORACLE_JAVA_9, ECLIPSE_JDT_JAVA_8),
/**
* Use all available processing variants
*/
ALL( ORACLE_JAVA_8, ORACLE_JAVA_9, ECLIPSE_JDT_JAVA_8, PROCESSOR_PLUGIN_JAVA_8 ),
/**
* Use all JDK8 compatible processing variants
*/
ALL_JAVA_8( ORACLE_JAVA_8, ECLIPSE_JDT_JAVA_8, PROCESSOR_PLUGIN_JAVA_8 );
private ProcessorType[] included = { };
private Toolchain toolchain;
private String compilerId;
private String sourceTargetVersion;
ProcessorType(Toolchain toolchain, String compilerId, String sourceTargetVersion) {
this.toolchain = toolchain;
this.compilerId = compilerId;
this.sourceTargetVersion = sourceTargetVersion;
}
ProcessorType(ProcessorType... included) {
this.included = included;
}
/**
* @return the processor types that are grouped by this type
*/
public ProcessorType[] getIncluded() {
return included;
}
/**
* @return the toolchain
*/
public Toolchain getToolchain() {
return toolchain;
}
/**
* @return the compilerId
*/
public String getCompilerId() {
return compilerId;
}
/**
* @return the sourceTargetVersion
*/
public String getSourceTargetVersion() {
return sourceTargetVersion;
}
}
/**
* Can be configured to provide additional command line arguments for the invoked Maven process, depending on the
* {@link ProcessorType} the test is executed for.
*
* @author Andreas Gudian
*/
interface CommandLineEnhancer {
/**
* @param processorType the processor type for which the test is executed.
* @return additional command line arguments to be passed to the Maven {@link Verifier}.
*/
Collection<String> getAdditionalCommandLineArguments(ProcessorType processorType);
}
/**
* @return a path in the classpath that contains the maven module to run as integration test: {@code mvn clean test}
*/
String baseDir();
/**
* @return the variants to execute the integration tests with. See {@link ProcessorType}.
*/
ProcessorType[] processorTypes() default { ProcessorType.ALL };
/**
* @return the {@link CommandLineEnhancer} implementation. Must have a default constructor.
*/
Class<? extends CommandLineEnhancer> commandLineEnhancer() default CommandLineEnhancer.class;
}

View File

@ -1,354 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.runner;
import static org.apache.maven.it.util.ResourceExtractor.extractResourceToDestination;
import static org.apache.maven.shared.utils.io.FileUtils.copyURLToFile;
import static org.apache.maven.shared.utils.io.FileUtils.deleteDirectory;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.apache.maven.it.Verifier;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.runners.model.EachTestNotifier;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runner.notification.StoppedByUserException;
import org.junit.runners.ParentRunner;
import org.junit.runners.model.InitializationError;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.CommandLineEnhancer;
import org.mapstruct.itest.testutil.runner.ProcessorSuite.ProcessorType;
import org.mapstruct.itest.testutil.runner.ProcessorSuiteRunner.ProcessorTestCase;
import org.mapstruct.itest.testutil.runner.xml.Toolchains;
import org.mapstruct.itest.testutil.runner.xml.Toolchains.ProviderDescription;
/**
* Runner for processor integration tests. Requires the annotation {@link ProcessorSuite} on the test class.
*
* @author Andreas Gudian
*/
public class ProcessorSuiteRunner extends ParentRunner<ProcessorTestCase> {
/**
* System property for specifying the location of the toolchains.xml file
*/
public static final String SYS_PROP_TOOLCHAINS_FILE = "processorIntegrationTest.toolchainsFile";
/**
* System property to enable remote debugging of the processor execution in the integration test
*/
public static final String SYS_PROP_DEBUG = "processorIntegrationTest.debug";
private static final File TOOLCHAINS_FILE = getToolchainsFile();
private static final Collection<ProcessorType> ENABLED_PROCESSOR_TYPES = detectSupportedTypes( TOOLCHAINS_FILE );
public static final class ProcessorTestCase {
private final String baseDir;
private final ProcessorType processor;
private final boolean ignored;
private final Constructor<? extends CommandLineEnhancer> cliEnhancerConstructor;
public ProcessorTestCase(String baseDir, ProcessorType processor,
Constructor<? extends CommandLineEnhancer> cliEnhancerConstructor) {
this.baseDir = baseDir;
this.processor = processor;
this.cliEnhancerConstructor = cliEnhancerConstructor;
this.ignored = !ENABLED_PROCESSOR_TYPES.contains( processor );
}
}
private final List<ProcessorTestCase> methods;
/**
* @param clazz the test class
* @throws InitializationError in case the initialization fails
*/
public ProcessorSuiteRunner(Class<?> clazz) throws InitializationError {
super( clazz );
ProcessorSuite suite = clazz.getAnnotation( ProcessorSuite.class );
if ( null == suite ) {
throw new InitializationError( "The test class must be annotated with " + ProcessorSuite.class.getName() );
}
if ( suite.processorTypes().length == 0 ) {
throw new InitializationError( "ProcessorSuite#processorTypes must not be empty" );
}
Constructor<? extends CommandLineEnhancer> cliEnhancerConstructor = null;
if ( suite.commandLineEnhancer() != CommandLineEnhancer.class ) {
try {
cliEnhancerConstructor = suite.commandLineEnhancer().getConstructor();
}
catch ( NoSuchMethodException e ) {
throw new InitializationError(
suite.commandLineEnhancer().getName() + " does not have a default constructor." );
}
catch ( SecurityException e ) {
throw new InitializationError( e );
}
}
methods = initializeTestCases( suite, cliEnhancerConstructor );
}
private List<ProcessorTestCase> initializeTestCases(ProcessorSuite suite,
Constructor<? extends CommandLineEnhancer> cliEnhancerConstructor) {
List<ProcessorType> types = new ArrayList<>();
for ( ProcessorType compiler : suite.processorTypes() ) {
if ( compiler.getIncluded().length > 0 ) {
types.addAll( Arrays.asList( compiler.getIncluded() ) );
}
else {
types.add( compiler );
}
}
List<ProcessorTestCase> result = new ArrayList<ProcessorTestCase>( types.size() );
for ( ProcessorType type : types ) {
result.add( new ProcessorTestCase( suite.baseDir(), type, cliEnhancerConstructor ) );
}
return result;
}
@Override
protected List<ProcessorTestCase> getChildren() {
return methods;
}
@Override
protected Description describeChild(ProcessorTestCase child) {
return Description.createTestDescription( getTestClass().getJavaClass(), child.processor.name().toLowerCase() );
}
@Override
protected void runChild(ProcessorTestCase child, RunNotifier notifier) {
Description description = describeChild( child );
EachTestNotifier testNotifier = new EachTestNotifier( notifier, description );
if ( child.ignored ) {
testNotifier.fireTestIgnored();
}
else {
try {
testNotifier.fireTestStarted();
doExecute( child, description );
}
catch ( AssumptionViolatedException e ) {
testNotifier.fireTestIgnored();
}
catch ( StoppedByUserException e ) {
throw e;
}
catch ( Throwable e ) {
testNotifier.addFailure( e );
}
finally {
testNotifier.fireTestFinished();
}
}
}
private void doExecute(ProcessorTestCase child, Description description) throws Exception {
File destination = extractTest( child, description );
PrintStream originalOut = System.out;
final Verifier verifier;
if ( Boolean.getBoolean( SYS_PROP_DEBUG ) ) {
if ( child.processor.getToolchain() == null ) {
// when not using toolchains for a test, then the compiler is executed within the Maven JVM. So make
// sure we fork a new JVM for that, and let that new JVM use the command 'mvnDebug' instead of 'mvn'
verifier = new Verifier( destination.getCanonicalPath(), null, true, true );
verifier.setDebugJvm( true );
}
else {
verifier = new Verifier( destination.getCanonicalPath() );
verifier.addCliOption( "-Pdebug-forked-javac" );
}
}
else {
verifier = new Verifier( destination.getCanonicalPath() );
}
List<String> goals = new ArrayList<>( 3 );
goals.add( "clean" );
try {
configureToolchains( child, verifier, goals, originalOut );
configureProcessor( child, verifier );
verifier.addCliOption( "-Dcompiler-source-target-version=" + child.processor.getSourceTargetVersion() );
verifier.addCliOption( "-Dmapstruct-artifact-id=mapstruct" );
if ( Boolean.getBoolean( SYS_PROP_DEBUG ) ) {
originalOut.print( "Processor Integration Test: " );
originalOut.println( "Listening for transport dt_socket at address: 8000 (in some seconds)" );
}
goals.add( "test" );
addAdditionalCliArguments( child, verifier );
originalOut.println( "executing " + child.processor.name().toLowerCase() );
verifier.executeGoals( goals );
verifier.verifyErrorFreeLog();
}
finally {
verifier.resetStreams();
}
}
private void addAdditionalCliArguments(ProcessorTestCase child, final Verifier verifier) throws Exception {
if ( child.cliEnhancerConstructor != null ) {
CommandLineEnhancer enhancer = child.cliEnhancerConstructor.newInstance();
Collection<String> additionalArgs = enhancer.getAdditionalCommandLineArguments( child.processor );
if ( additionalArgs != null ) {
for ( String arg : additionalArgs ) {
verifier.addCliOption( arg );
}
}
}
}
private void configureProcessor(ProcessorTestCase child, Verifier verifier) {
if ( child.processor.getCompilerId() != null ) {
verifier.addCliOption( "-Pgenerate-via-compiler-plugin" );
verifier.addCliOption( "-Dcompiler-id=" + child.processor.getCompilerId() );
}
else {
verifier.addCliOption( "-Pgenerate-via-processor-plugin" );
}
}
private void configureToolchains(ProcessorTestCase child, Verifier verifier, List<String> goals,
PrintStream originalOut) {
if ( child.processor.getToolchain() != null ) {
verifier.addCliOption( "--toolchains" );
verifier.addCliOption( TOOLCHAINS_FILE.getPath().replace( '\\', '/' ) );
Toolchain toolchain = child.processor.getToolchain();
verifier.addCliOption( "-Dtoolchain-jdk-vendor=" + toolchain.getVendor() );
verifier.addCliOption( "-Dtoolchain-jdk-version=" + toolchain.getVersionRangeString() );
goals.add( "toolchains:toolchain" );
}
}
private File extractTest(ProcessorTestCase child, Description description) throws IOException {
File tempDirBase = new File( "target/tmp", description.getClassName() ).getCanonicalFile();
if ( !tempDirBase.exists() ) {
tempDirBase.mkdirs();
}
File parentPom = new File( tempDirBase, "pom.xml" );
copyURLToFile( getClass().getResource( "/pom.xml" ), parentPom );
File tempDir = new File( tempDirBase, description.getMethodName() );
deleteDirectory( tempDir );
return extractResourceToDestination( getClass(), "/" + child.baseDir, tempDir, true );
}
private static File getToolchainsFile() {
String specifiedToolchainsFile = System.getProperty( SYS_PROP_TOOLCHAINS_FILE );
if ( null != specifiedToolchainsFile ) {
try {
File canonical = new File( specifiedToolchainsFile ).getCanonicalFile();
if ( canonical.exists() ) {
return canonical;
}
// check the path relative to the parent directory (allows specifying a path relative to the top-level
// aggregator module)
canonical = new File( "..", specifiedToolchainsFile ).getCanonicalFile();
if ( canonical.exists() ) {
return canonical;
}
}
catch ( IOException e ) {
return null;
}
}
// use default location
String defaultPath = System.getProperty( "user.home" ) + System.getProperty( "file.separator" ) + ".m2";
return new File( defaultPath, "toolchains.xml" );
}
private static Collection<ProcessorType> detectSupportedTypes(File toolchainsFile) {
Toolchains toolchains;
try {
if ( toolchainsFile.exists() ) {
Unmarshaller unmarshaller = JAXBContext.newInstance( Toolchains.class ).createUnmarshaller();
toolchains = (Toolchains) unmarshaller.unmarshal( toolchainsFile );
}
else {
toolchains = null;
}
}
catch ( JAXBException e ) {
toolchains = null;
}
Collection<ProcessorType> supported = new HashSet<>();
for ( ProcessorType type : ProcessorType.values() ) {
if ( isSupported( type, toolchains ) ) {
supported.add( type );
}
}
return supported;
}
private static boolean isSupported(ProcessorType type, Toolchains toolchains) {
if ( type.getToolchain() == null ) {
return true;
}
if ( toolchains == null ) {
return false;
}
Toolchain required = type.getToolchain();
for ( Toolchains.Toolchain tc : toolchains.getToolchains() ) {
if ( "jdk".equals( tc.getType() ) ) {
ProviderDescription desc = tc.getProviderDescription();
if ( desc != null
&& required.getVendor().equals( desc.getVendor() )
&& desc.getVersion() != null
&& desc.getVersion().startsWith( required.getVersionMinInclusive() ) ) {
return true;
}
}
}
return false;
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.runner;
/**
* Describes a required entry in the Maven toolchains.xml file.
*
* @author Andreas Gudian
*/
class Toolchain {
private final String vendor;
private final String versionMinInclusive;
private final String versionMaxExclusive;
Toolchain(String vendor, String versionMinInclusive, String versionMaxExclusive) {
this.vendor = vendor;
this.versionMinInclusive = versionMinInclusive;
this.versionMaxExclusive = versionMaxExclusive;
}
String getVendor() {
return vendor;
}
String getVersionMinInclusive() {
return versionMinInclusive;
}
/**
* @return the version range string to be used in the Maven execution to select the toolchain
*/
String getVersionRangeString() {
return "[" + versionMinInclusive + "," + versionMaxExclusive + ")";
}
}

View File

@ -1,74 +0,0 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.itest.testutil.runner.xml;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* JAXB representation of some of the parts in the Maven toolchains.xml file.
*
* @author Andreas Gudian
*/
@XmlRootElement
public class Toolchains {
@XmlElement(name = "toolchain")
private List<Toolchain> toolchains = new ArrayList<>();
public List<Toolchain> getToolchains() {
return toolchains;
}
@Override
public String toString() {
return "Toolchains [toolchains=" + toolchains + "]";
}
public static class Toolchain {
@XmlElement
private String type;
@XmlElement(name = "provides")
private ProviderDescription providerDescription;
public String getType() {
return type;
}
public ProviderDescription getProviderDescription() {
return providerDescription;
}
@Override
public String toString() {
return "Toolchain [type=" + type + ", providerDescription=" + providerDescription + "]";
}
}
public static class ProviderDescription {
@XmlElement
private String version;
@XmlElement
private String vendor;
public String getVersion() {
return version;
}
public String getVendor() {
return vendor;
}
@Override
public String toString() {
return "ProviderDescription [version=" + version + ", vendor=" + vendor + "]";
}
}
}

View File

@ -76,4 +76,25 @@
<artifactId>joda-time</artifactId>
</dependency>
</dependencies>
<profiles>
<profile>
<id>jdk-11-or-newer</id>
<activation>
<jdk>[11</jdk>
</activation>
<dependencies>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>
</dependencies>
</profile>
</profiles>
</project>

View File

@ -50,4 +50,26 @@
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>jdk-11-or-newer</id>
<activation>
<jdk>[11</jdk>
</activation>
<dependencies>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>
</dependencies>
</profile>
</profiles>
</project>

View File

@ -24,9 +24,6 @@
<properties>
<mapstruct.version>${mapstruct.version}</mapstruct.version>
<mapstruct-artifact-id>mapstruct</mapstruct-artifact-id>
<toolchain-jdk-version></toolchain-jdk-version>
<toolchain-jdk-vendor></toolchain-jdk-vendor>
<compiler-id></compiler-id>
<compiler-source-target-version></compiler-source-target-version>
<!-- As Mapstruct has java 6 requirement we need to use AssertJ 1.x which is compatible with java 6 -->
@ -137,7 +134,7 @@
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>\${mapstruct-artifact-id}</artifactId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
<scope>provided</scope>
</dependency>
@ -165,19 +162,6 @@
<target>\${compiler-source-target-version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<version>1.0</version>
<configuration>
<toolchains>
<jdk>
<version>\${toolchain-jdk-version}</version>
<vendor>\${toolchain-jdk-vendor}</vendor>
</jdk>
</toolchains>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>

View File

@ -29,6 +29,7 @@
<org.springframework.version>4.0.3.RELEASE</org.springframework.version>
<org.eclipse.tycho.compiler-jdt.version>0.26.0</org.eclipse.tycho.compiler-jdt.version>
<com.puppycrawl.tools.checkstyle.version>8.29</com.puppycrawl.tools.checkstyle.version>
<org.junit.jupiter.version>5.6.0</org.junit.jupiter.version>
<add.release.arguments />
<forkCount>1</forkCount>
<assertj.version>3.11.1</assertj.version>
@ -129,6 +130,14 @@
<version>${com.puppycrawl.tools.checkstyle.version}</version>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${org.junit.jupiter.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- CDI, Weld, Arquillian -->
<dependency>
<groupId>javax.enterprise</groupId>
@ -189,7 +198,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<version>1.18.10</version>
</dependency>
<dependency>
<groupId>org.immutables</groupId>
@ -573,12 +582,12 @@
<exclude>copyright.txt</exclude>
<exclude>**/LICENSE.txt</exclude>
<exclude>**/mapstruct.xml</exclude>
<exclude>**/toolchains-*.xml</exclude>
<exclude>**/travis-settings.xml</exclude>
<exclude>**/eclipse-formatter-config.xml</exclude>
<exclude>**/forbidden-apis.txt</exclude>
<exclude>**/checkstyle-for-generated-sources.xml</exclude>
<exclude>**/nb-configuration.xml</exclude>
<exclude>**/junit-platform.properties</exclude>
<exclude>maven-settings.xml</exclude>
<exclude>readme.md</exclude>
<exclude>CONTRIBUTING.md</exclude>