Skip to content

Commit 5bbd1a7

Browse files
committed
Migrate the processor test infrastructure from JUnit 4 to JUnit Jupiter
With JUnit Jupiter it is still not possible to set the ClassLoader for loading the test class. However, since 5.8 M1 there is a way to hook into the launcher discovery process and change the Current Thread ContextClassLoader which would load the classes with our customer ClassLoader. Once JUnit Jupiter 201 is resolved we can simplify this. The CompilationCache is stored in the GlobalCache with the CompilationRequest as key. This means that even when methods are not executed in some particular order if they have same WithClasses then they would reuse the cache.
1 parent 51cdbd6 commit 5bbd1a7

22 files changed

Lines changed: 373 additions & 783 deletions

parent/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
<org.springframework.version>5.3.3</org.springframework.version>
2929
<org.eclipse.tycho.compiler-jdt.version>1.6.0</org.eclipse.tycho.compiler-jdt.version>
3030
<com.puppycrawl.tools.checkstyle.version>8.36.1</com.puppycrawl.tools.checkstyle.version>
31-
<org.junit.jupiter.version>5.7.0</org.junit.jupiter.version>
31+
<org.junit.jupiter.version>5.8.0-M1</org.junit.jupiter.version>
3232
<add.release.arguments />
3333
<forkCount>1</forkCount>
3434
<assertj.version>3.17.2</assertj.version>

processor/pom.xml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,13 @@
4949
</dependency>
5050
<!-- Test -->
5151
<dependency>
52-
<groupId>junit</groupId>
53-
<artifactId>junit</artifactId>
52+
<groupId>org.junit.jupiter</groupId>
53+
<artifactId>junit-jupiter-api</artifactId>
54+
<scope>test</scope>
55+
</dependency>
56+
<dependency>
57+
<groupId>org.junit.jupiter</groupId>
58+
<artifactId>junit-jupiter-engine</artifactId>
5459
<scope>test</scope>
5560
</dependency>
5661
<dependency>
@@ -104,6 +109,12 @@
104109
<scope>test</scope>
105110
</dependency>
106111

112+
<dependency>
113+
<groupId>org.junit.platform</groupId>
114+
<artifactId>junit-platform-launcher</artifactId>
115+
<scope>test</scope>
116+
</dependency>
117+
107118
<!-- There is no compile dependency to Joda-Time; It's only required for testing the Joda conversions -->
108119
<dependency>
109120
<groupId>joda-time</groupId>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.ap.testutil;
7+
8+
import java.lang.annotation.Documented;
9+
import java.lang.annotation.ElementType;
10+
import java.lang.annotation.Retention;
11+
import java.lang.annotation.RetentionPolicy;
12+
import java.lang.annotation.Target;
13+
14+
import org.junit.jupiter.api.TestTemplate;
15+
import org.junit.jupiter.api.extension.ExtendWith;
16+
import org.mapstruct.ap.testutil.runner.Compiler;
17+
import org.mapstruct.ap.testutil.runner.ProcessorTestExtension;
18+
19+
/**
20+
* JUnit Jupiter test template for the MapStruct Processor tests.
21+
* <p>
22+
* Test classes are safe to be executed in parallel, but test methods are not safe to be executed in parallel.
23+
* <p>
24+
* By default this template would generate tests for the JDK and Eclipse Compiler.
25+
* If only a single compiler is needed then specify the compiler in the value.
26+
* <p>
27+
* The classes to be compiled for a given test method must be specified via {@link WithClasses}. In addition the
28+
* following things can be configured optionally :
29+
* <ul>
30+
* <li>Processor options to be considered during compilation via
31+
* {@link org.mapstruct.ap.testutil.compilation.annotation.ProcessorOption ProcessorOption}.</li>
32+
* <li>The expected compilation outcome and expected diagnostics can be specified via
33+
* {@link org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome ExpectedCompilationOutcome}.
34+
* If no outcome is specified, a successful compilation is assumed.</li>
35+
* </ul>
36+
*
37+
* @author Filip Hrisafov
38+
*/
39+
@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
40+
@Retention(RetentionPolicy.RUNTIME)
41+
@Documented
42+
@TestTemplate
43+
@ExtendWith(ProcessorTestExtension.class)
44+
public @interface ProcessorTest {
45+
46+
Compiler[] value() default {
47+
Compiler.JDK,
48+
Compiler.ECLIPSE
49+
};
50+
}

processor/src/test/java/org/mapstruct/ap/testutil/runner/AnnotationProcessorTestRunner.java

Lines changed: 0 additions & 160 deletions
This file was deleted.

processor/src/test/java/org/mapstruct/ap/testutil/runner/CompilationRequest.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@
1313
* Represents a compilation task for a number of sources with given processor options.
1414
*/
1515
public class CompilationRequest {
16+
private final Compiler compiler;
1617
private final Set<Class<?>> sourceClasses;
1718
private final Map<Class<?>, Class<?>> services;
1819
private final List<String> processorOptions;
1920

20-
CompilationRequest(Set<Class<?>> sourceClasses, Map<Class<?>, Class<?>> services, List<String> processorOptions) {
21+
CompilationRequest(Compiler compiler, Set<Class<?>> sourceClasses, Map<Class<?>, Class<?>> services,
22+
List<String> processorOptions) {
23+
this.compiler = compiler;
2124
this.sourceClasses = sourceClasses;
2225
this.services = services;
2326
this.processorOptions = processorOptions;
@@ -27,6 +30,7 @@ public class CompilationRequest {
2730
public int hashCode() {
2831
final int prime = 31;
2932
int result = 1;
33+
result = prime * result + ( ( compiler == null ) ? 0 : compiler.hashCode() );
3034
result = prime * result + ( ( processorOptions == null ) ? 0 : processorOptions.hashCode() );
3135
result = prime * result + ( ( services == null ) ? 0 : services.hashCode() );
3236
result = prime * result + ( ( sourceClasses == null ) ? 0 : sourceClasses.hashCode() );
@@ -46,7 +50,8 @@ public boolean equals(Object obj) {
4650
}
4751
CompilationRequest other = (CompilationRequest) obj;
4852

49-
return processorOptions.equals( other.processorOptions )
53+
return compiler.equals( other.compiler )
54+
&& processorOptions.equals( other.processorOptions )
5055
&& services.equals( other.services )
5156
&& sourceClasses.equals( other.sourceClasses );
5257
}

processor/src/test/java/org/mapstruct/ap/testutil/runner/Compiler.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,27 @@
55
*/
66
package org.mapstruct.ap.testutil.runner;
77

8+
import org.junit.jupiter.api.condition.JRE;
9+
810
/**
911
* @author Andreas Gudian
10-
*
12+
* @author Filip Hrisafov
1113
*/
1214
public enum Compiler {
13-
JDK, JDK11, ECLIPSE, ECLIPSE11;
15+
JDK,
16+
ECLIPSE;
17+
18+
private final JRE latestSupportedJre;
19+
20+
Compiler() {
21+
this( JRE.OTHER );
22+
}
23+
24+
Compiler(JRE latestSupportedJre) {
25+
this.latestSupportedJre = latestSupportedJre;
26+
}
27+
28+
public JRE latestSupportedJre() {
29+
return latestSupportedJre;
30+
}
1431
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.ap.testutil.runner;
7+
8+
import org.junit.platform.engine.UniqueId;
9+
import org.junit.platform.launcher.LauncherDiscoveryListener;
10+
11+
/**
12+
* @author Filip Hrisafov
13+
*/
14+
public class CompilerLauncherDiscoveryListener implements LauncherDiscoveryListener {
15+
@Override
16+
public void engineDiscoveryStarted(UniqueId engineId) {
17+
// Currently JUnit Jupiter does not have an SPI for providing a ClassLoader for loading the class
18+
// However, we can change the current context class loaded when the engine discovery starts.
19+
// This would make sure that JUnit Jupiter uses our ClassLoader to correctly load the mappers
20+
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
21+
FilteringParentClassLoader filteringParentClassLoader = new FilteringParentClassLoader(
22+
currentClassLoader,
23+
"org.mapstruct.ap.test."
24+
);
25+
ModifiableURLClassLoader newClassLoader = new ModifiableURLClassLoader( filteringParentClassLoader );
26+
newClassLoader.withOriginOf( getClass() );
27+
Thread.currentThread().setContextClassLoader( newClassLoader );
28+
}
29+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright MapStruct Authors.
3+
*
4+
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
package org.mapstruct.ap.testutil.runner;
7+
8+
import org.junit.jupiter.api.condition.JRE;
9+
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
10+
import org.junit.jupiter.api.extension.ExecutionCondition;
11+
import org.junit.jupiter.api.extension.ExtensionContext;
12+
13+
/**
14+
* Every compiler is registered with it's max supported JRE that it can run on.
15+
* This condition is used to check if the test for a particular compiler can be run with the current JRE.
16+
*
17+
* @author Filip Hrisafov
18+
*/
19+
public class CompilerTestEnabledOnJreCondition implements ExecutionCondition {
20+
21+
static final ConditionEvaluationResult ENABLED_ON_CURRENT_JRE =
22+
ConditionEvaluationResult.enabled( "Enabled on JRE version: " + System.getProperty( "java.version" ) );
23+
24+
static final ConditionEvaluationResult DISABLED_ON_CURRENT_JRE =
25+
ConditionEvaluationResult.disabled( "Disabled on JRE version: " + System.getProperty( "java.version" ) );
26+
27+
protected final Compiler compiler;
28+
29+
public CompilerTestEnabledOnJreCondition(Compiler compiler) {
30+
this.compiler = compiler;
31+
}
32+
33+
@Override
34+
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
35+
// If the max JRE is greater or equal to the current version the test is enabled
36+
return compiler.latestSupportedJre().compareTo( JRE.currentVersion() ) >= 0 ? ENABLED_ON_CURRENT_JRE :
37+
DISABLED_ON_CURRENT_JRE;
38+
}
39+
}

0 commit comments

Comments
 (0)