You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ti...@apache.org on 2018/05/03 20:02:31 UTC
[maven-surefire] 01/01: [SUREFIRE-1330] JUnit 5 surefire-provider
code donation
This is an automated email from the ASF dual-hosted git repository.
tibordigana pushed a commit to branch new-junit5
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
commit e61f2bef5a7f840cf7a57dde63c05f166235e37e
Author: Tibor17 <ti...@apache.org>
AuthorDate: Fri Apr 13 23:51:33 2018 +0200
[SUREFIRE-1330] JUnit 5 surefire-provider code donation
---
.../plugin/surefire/AbstractSurefireMojo.java | 46 +-
pom.xml | 7 +-
surefire-its/pom.xml | 23 +-
.../maven/surefire/its/JUnit4VersionsIT.java | 74 +-
.../org/apache/maven/surefire/its/JUnit5IT.java} | 50 +-
.../maven/surefire/its/JUnitPlatformIT.java} | 48 +-
.../apache/maven/surefire/its/JUnitVersion.java | 80 +++
.../resources/{junit4 => junit-platform}/pom.xml | 55 +-
.../src/test/java/junitplatform}/BasicTest.java | 30 +-
surefire-its/src/test/resources/junit4/pom.xml | 141 +++-
.../junit4/src/test/java/junit4/BasicTest.java | 4 +-
.../BasicTest.java => junit5/JUnit5Test.java} | 35 +-
surefire-its/src/test/resources/junit5/pom.xml | 77 +++
.../src/test/java/junit5/JUnit4Test.java} | 19 +-
.../src/test/java/junit5/JUnit5Test.java} | 36 +-
surefire-providers/pom.xml | 1 +
surefire-providers/surefire-junit-platform/pom.xml | 161 +++++
.../junitplatform/JUnitPlatformProvider.java | 241 +++++++
.../surefire/junitplatform/RunListenerAdapter.java | 272 ++++++++
.../surefire/junitplatform/TestMethodFilter.java | 60 ++
.../junitplatform/TestPlanScannerFilter.java | 60 ++
...che.maven.surefire.providerapi.SurefireProvider | 1 +
.../junitplatform/JUnitPlatformProviderTests.java | 756 +++++++++++++++++++++
.../junitplatform/RunListenerAdapterTests.java | 580 ++++++++++++++++
.../junitplatform/TestMethodFilterTests.java | 105 +++
.../junitplatform/TestPlanScannerFilterTests.java | 188 +++++
26 files changed, 2910 insertions(+), 240 deletions(-)
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
index 34f805a..414e084 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java
@@ -1024,6 +1024,7 @@ public abstract class AbstractSurefireMojo
new TestNgProviderInfo( getTestNgArtifact() ),
new JUnitCoreProviderInfo( getJunitArtifact(), junitDepArtifact ),
new JUnit4ProviderInfo( getJunitArtifact(), junitDepArtifact ),
+ new JUnitPlatformProviderInfo( getJunitArtifact() ),
new JUnit3ProviderInfo() )
.resolve();
}
@@ -1540,7 +1541,17 @@ public abstract class AbstractSurefireMojo
return dependencyResolver.isWithinVersionSpec( artifact, "[4.0,)" );
}
- static boolean isForkModeNever( String forkMode )
+ private boolean isJunitJupiter( Artifact artifact )
+ {
+ return dependencyResolver.isWithinVersionSpec( artifact, "[5.0.0,)" );
+ }
+
+ private boolean isJunitVintage( Artifact artifact )
+ {
+ return dependencyResolver.isWithinVersionSpec( artifact, "[4.12.0,5.0.0)" );
+ }
+
+ private static boolean isForkModeNever( String forkMode )
{
return FORK_NEVER.equals( forkMode );
}
@@ -2873,6 +2884,39 @@ public abstract class AbstractSurefireMojo
}
+ final class JUnitPlatformProviderInfo
+ implements ProviderInfo
+ {
+ private final Artifact junitArtifact;
+
+ JUnitPlatformProviderInfo( Artifact junitArtifact )
+ {
+ this.junitArtifact = junitArtifact;
+ }
+
+ @Nonnull public String getProviderName()
+ {
+ return "org.apache.maven.surefire.junitplatform.JUnitPlatformProvider";
+ }
+
+ public boolean isApplicable()
+ {
+ return isJunitJupiter( junitArtifact ) || isJunitVintage( junitArtifact );
+ }
+
+ public void addProviderProperties() throws MojoExecutionException
+ {
+ }
+
+ public Classpath getProviderClasspath()
+ throws ArtifactResolutionException, ArtifactNotFoundException
+ {
+ return dependencyResolver.getProviderClasspath( "surefire-junit-platform",
+ surefireBooterArtifact.getBaseVersion(),
+ null );
+ }
+ }
+
final class JUnitCoreProviderInfo
implements ProviderInfo
{
diff --git a/pom.xml b/pom.xml
index 5fdefd4..96a75a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,8 +97,9 @@
<maven.site.path>surefire-archives/surefire-LATEST</maven.site.path>
<!-- Override with Jigsaw JRE 9 -->
<jdk.home>${java.home}/..</jdk.home>
- <maven.compiler.testSource>1.6</maven.compiler.testSource>
- <maven.compiler.testTarget>1.6</maven.compiler.testTarget>
+ <javaVersion>6</javaVersion>
+ <maven.compiler.testSource>1.${javaVersion}</maven.compiler.testSource>
+ <maven.compiler.testTarget>1.${javaVersion}</maven.compiler.testTarget>
<jvm.args.tests>-server -XX:+UseG1GC -Xms128m -Xmx144m -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:SoftRefLRUPolicyMSPerMB=50 -Djava.awt.headless=true</jvm.args.tests>
</properties>
@@ -419,6 +420,7 @@
<excludeDependencies>
<param>org.codehaus.plexus:plexus-java</param>
<param>org.ow2.asm:asm</param>
+ <param>org.junit.platform:junit-platform-commons</param>
</excludeDependencies>
<ignores>
<param>org.objectweb.asm.*</param>
@@ -550,6 +552,7 @@
<excludes>
<exclude>org.codehaus.plexus:plexus-java</exclude>
<exclude>org.ow2.asm:asm</exclude>
+ <exclude>org.junit.platform:junit-platform-commons</exclude>
</excludes>
</enforceBytecodeVersion>
</rules>
diff --git a/surefire-its/pom.xml b/surefire-its/pom.xml
index 88a4870..d4c7df4 100644
--- a/surefire-its/pom.xml
+++ b/surefire-its/pom.xml
@@ -104,7 +104,9 @@
<forkMode>once</forkMode>
<argLine>-server -Xmx64m -XX:+UseG1GC -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Djava.awt.headless=true</argLine>
<includes>
- <include>org/apache/**/*IT*.java</include>
+ <include>org/apache/**/JUnit4VersionsIT.java</include>
+ <include>org/apache/**/JUnit5IT.java</include>
+ <include>org/apache/**/JUnitPlatformIT.java</include>
</includes>
<!-- Pass current surefire version to the main suite so that it -->
<!-- can forward to all integration test projects. SUREFIRE-513 -->
@@ -143,25 +145,6 @@
</executions>
</plugin>
<plugin>
- <artifactId>maven-enforcer-plugin</artifactId>
- <executions>
- <execution>
- <id>require-maven-2.1.0</id>
- <goals>
- <goal>enforce</goal>
- </goals>
- <configuration>
- <rules>
- <requireMavenVersion>
- <!-- Some plugin features require a recent Maven runtime to work (e.g. SystemPropertiesTest) -->
- <version>[2.1.0,)</version>
- </requireMavenVersion>
- </rules>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
<artifactId>maven-jar-plugin</artifactId>
<!-- todo dont skip since of failsafe:2.19 internal use if having src/main/java/... -->
<configuration>
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit4VersionsIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit4VersionsIT.java
index 8dd8f0c..c391964 100644
--- a/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit4VersionsIT.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit4VersionsIT.java
@@ -19,7 +19,6 @@ package org.apache.maven.surefire.its;
* under the License.
*/
-import java.util.Arrays;
import java.util.Collection;
import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
@@ -29,8 +28,28 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
+import static java.util.Arrays.asList;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_10;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_11;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_12;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_8;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_8_1;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_8_2;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_9;
import static org.junit.runners.Parameterized.*;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_0;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_1;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_2;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_3;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_3_1;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_4;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_5;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_6;
+import static org.apache.maven.surefire.its.JUnitVersion.JUNIT_4_7;
+import static org.apache.maven.surefire.its.JUnitVersion.JUPITER_5_1_1;
+import static org.apache.maven.surefire.its.JUnitVersion.VINTAGE_5_1_1;
+
/**
* Basic suite test using all known versions of JUnit 4.x
*
@@ -44,44 +63,41 @@ public class JUnit4VersionsIT
@Parameters( name = "{index}: JUnit {0}" )
public static Collection<Object[]> junitVersions()
{
- return Arrays.asList( new Object[][] {
- { "4.0" },
- { "4.1" },
- { "4.2" },
- { "4.3" },
- { "4.3.1" },
- { "4.4" },
- { "4.5" },
- { "4.6" },
- { "4.7" },
- { "4.8" },
- { "4.8.1" },
- { "4.8.2" },
- { "4.9" },
- { "4.10" },
- { "4.11" },
- { "4.12" }
+ return asList( new Object[][] {
+ { JUNIT_4_0 },
+ { JUNIT_4_1 },
+ { JUNIT_4_2 },
+ { JUNIT_4_3 },
+ { JUNIT_4_3_1 },
+ { JUNIT_4_4 },
+ { JUNIT_4_5 },
+ { JUNIT_4_6 },
+ { JUNIT_4_7 },
+ { JUNIT_4_8 },
+ { JUNIT_4_8_1 },
+ { JUNIT_4_8_2 },
+ { JUNIT_4_9 },
+ { JUNIT_4_10 },
+ { JUNIT_4_11 },
+ { JUNIT_4_12 },
+ { VINTAGE_5_1_1 },
+ { JUPITER_5_1_1 }
} );
}
@Parameter
- public String version;
-
- private SurefireLauncher unpack()
- {
- return unpack( "/junit4", version );
- }
+ public JUnitVersion version;
@Test
public void testJunit()
- throws Exception
{
- runJUnitTest( version );
+ version.configure( unpack() )
+ .executeTest()
+ .verifyErrorFree( 1 );
}
- public void runJUnitTest( String version )
- throws Exception
+ private SurefireLauncher unpack()
{
- unpack().setJUnitVersion( version ).executeTest().verifyErrorFree( 1 );
+ return unpack( "/junit4", version.toString() );
}
}
diff --git a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit5IT.java
similarity index 54%
copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
copy to surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit5IT.java
index e9234f2..8c5eb3a 100644
--- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnit5IT.java
@@ -1,4 +1,4 @@
-package junit4;
+package org.apache.maven.surefire.its;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,47 +19,27 @@ package junit4;
* under the License.
*/
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
+import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
import org.junit.Test;
+import static org.apache.maven.surefire.its.fixture.HelperAssertions.assumeJavaVersion;
-public class BasicTest
+/**
+ * Basic suite test currently only running against JUnit 5 M2
+ *
+ * @author <a href="mailto:britter@apache.org">Benedikt Ritter</a>
+ */
+public class JUnit5IT
+ extends SurefireJUnit4IntegrationTestCase
{
- private boolean setUpCalled = false;
-
- private static boolean tearDownCalled = false;
-
- @Before
- public void setUp()
- {
- setUpCalled = true;
- tearDownCalled = false;
- System.out.println( "Called setUp" );
- }
-
- @After
- public void tearDown()
- {
- setUpCalled = false;
- tearDownCalled = true;
- System.out.println( "Called tearDown" );
- }
-
@Test
- public void testSetUp()
+ public void test()
{
- Assert.assertTrue( "setUp was not called", setUpCalled );
- }
-
+ assumeJavaVersion( 1.8d );
- @AfterClass
- public static void oneTimeTearDown()
- {
-
+ unpack( "/junit5" )
+ .executeTest()
+ .verifyErrorFree( 2 );
}
-
}
diff --git a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitPlatformIT.java
similarity index 53%
copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
copy to surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitPlatformIT.java
index e9234f2..f82206c 100644
--- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitPlatformIT.java
@@ -1,4 +1,4 @@
-package junit4;
+package org.apache.maven.surefire.its;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,47 +19,29 @@ package junit4;
* under the License.
*/
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
+import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.apache.maven.surefire.its.fixture.SurefireLauncher;
import org.junit.Test;
+import static java.lang.System.getProperty;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assume.assumeThat;
-public class BasicTest
+public class JUnitPlatformIT
+ extends SurefireJUnit4IntegrationTestCase
{
-
- private boolean setUpCalled = false;
-
- private static boolean tearDownCalled = false;
-
- @Before
- public void setUp()
- {
- setUpCalled = true;
- tearDownCalled = false;
- System.out.println( "Called setUp" );
- }
-
- @After
- public void tearDown()
+ private SurefireLauncher unpack()
{
- setUpCalled = false;
- tearDownCalled = true;
- System.out.println( "Called tearDown" );
+ return unpack( "/junit-platform" );
}
@Test
- public void testSetUp()
+ public void test40()
{
- Assert.assertTrue( "setUp was not called", setUpCalled );
- }
-
+ assumeThat( "java.specification.version: ",
+ getProperty( "java.specification.version" ), is( greaterThanOrEqualTo( "1.8" ) ) );
- @AfterClass
- public static void oneTimeTearDown()
- {
-
+ unpack().executeTest().verifyErrorFree( 1 );
}
-
}
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitVersion.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitVersion.java
new file mode 100644
index 0000000..8e7f606
--- /dev/null
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitVersion.java
@@ -0,0 +1,80 @@
+package org.apache.maven.surefire.its;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.maven.surefire.its.fixture.SurefireLauncher;
+
+/**
+ * Enum listing all the JUnit version.
+ */
+public enum JUnitVersion {
+
+ JUNIT_4_0( "4.0" ),
+ JUNIT_4_1( "4.1" ),
+ JUNIT_4_2( "4.2" ),
+ JUNIT_4_3( "4.3" ),
+ JUNIT_4_3_1( "4.3.1" ),
+ JUNIT_4_4( "4.4" ),
+ JUNIT_4_5( "4.5" ),
+ JUNIT_4_6( "4.6" ),
+ JUNIT_4_7( "4.7" ),
+ JUNIT_4_8( "4.8" ),
+ JUNIT_4_8_1( "4.8.1" ),
+ JUNIT_4_8_2( "4.8.2" ),
+ JUNIT_4_9( "4.9" ),
+ JUNIT_4_10( "4.10" ),
+ JUNIT_4_11( "4.11" ),
+ JUNIT_4_12( "4.12" ),
+ VINTAGE_5_1_1( "5.1.1" )
+ {
+ @Override
+ public SurefireLauncher configure( SurefireLauncher launcher )
+ {
+ return super.configure( launcher )
+ .activateProfile( "junit5-vintage" );
+ }
+ },
+ JUPITER_5_1_1( "5.1.1" )
+ {
+ @Override
+ public SurefireLauncher configure( SurefireLauncher launcher )
+ {
+ return super.configure( launcher )
+ .activateProfile( "junit5-jupiter" );
+ }
+ };
+
+ private final String version;
+
+ JUnitVersion( String version )
+ {
+ this.version = version;
+ }
+
+ public SurefireLauncher configure( SurefireLauncher launcher )
+ {
+ return launcher.setJUnitVersion( version );
+ }
+
+ public String toString()
+ {
+ return version;
+ }
+}
diff --git a/surefire-its/src/test/resources/junit4/pom.xml b/surefire-its/src/test/resources/junit-platform/pom.xml
similarity index 55%
copy from surefire-its/src/test/resources/junit4/pom.xml
copy to surefire-its/src/test/resources/junit-platform/pom.xml
index 751a0e6..40a4f61 100644
--- a/surefire-its/src/test/resources/junit4/pom.xml
+++ b/surefire-its/src/test/resources/junit-platform/pom.xml
@@ -17,39 +17,38 @@
~ specific language governing permissions and limitations
~ under the License.
-->
+
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
+ <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.maven.plugins.surefire</groupId>
- <artifactId>junit4</artifactId>
- <version>1.0-SNAPSHOT</version>
- <name>Test for JUnit 4</name>
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>junit-platform</artifactId>
+ <version>1.0</version>
+ <name>Test for JUnit 5 Platform</name>
- <properties>
- <junitVersion>4.4</junitVersion>
- <maven.compiler.source>1.6</maven.compiler.source>
- <maven.compiler.target>1.6</maven.compiler.target>
- </properties>
+ <properties>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+ </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>${junit.version}</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>${surefire.version}</version>
- </plugin>
- </plugins>
- </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <version>5.1.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ </plugin>
+ </plugins>
+ </build>
</project>
diff --git a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java b/surefire-its/src/test/resources/junit-platform/src/test/java/junitplatform/BasicTest.java
similarity index 73%
copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
copy to surefire-its/src/test/resources/junit-platform/src/test/java/junitplatform/BasicTest.java
index e9234f2..2c9d119 100644
--- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
+++ b/surefire-its/src/test/resources/junit-platform/src/test/java/junitplatform/BasicTest.java
@@ -1,4 +1,4 @@
-package junit4;
+package junitplatform;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,21 +19,21 @@ package junit4;
* under the License.
*/
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
public class BasicTest
{
- private boolean setUpCalled = false;
+ private boolean setUpCalled;
- private static boolean tearDownCalled = false;
-
- @Before
+ private static boolean tearDownCalled;
+
+ @BeforeEach
public void setUp()
{
setUpCalled = true;
@@ -41,7 +41,7 @@ public class BasicTest
System.out.println( "Called setUp" );
}
- @After
+ @AfterEach
public void tearDown()
{
setUpCalled = false;
@@ -52,14 +52,14 @@ public class BasicTest
@Test
public void testSetUp()
{
- Assert.assertTrue( "setUp was not called", setUpCalled );
+ assertTrue( setUpCalled, "setUp was not called" );
}
-
- @AfterClass
+
+ @AfterAll
public static void oneTimeTearDown()
{
-
+ assertTrue( tearDownCalled );
}
}
diff --git a/surefire-its/src/test/resources/junit4/pom.xml b/surefire-its/src/test/resources/junit4/pom.xml
index 751a0e6..deddd56 100644
--- a/surefire-its/src/test/resources/junit4/pom.xml
+++ b/surefire-its/src/test/resources/junit4/pom.xml
@@ -20,36 +20,121 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
+ <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.maven.plugins.surefire</groupId>
- <artifactId>junit4</artifactId>
- <version>1.0-SNAPSHOT</version>
- <name>Test for JUnit 4</name>
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>junit4</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <name>Test for JUnit 4</name>
- <properties>
- <junitVersion>4.4</junitVersion>
- <maven.compiler.source>1.6</maven.compiler.source>
- <maven.compiler.target>1.6</maven.compiler.target>
- </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <version>5.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>${junit.version}</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>${surefire.version}</version>
- </plugin>
- </plugins>
- </build>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>junit4</id>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junit.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>junit5-jupiter</id>
+ <properties>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <junit.jupiter.version>5.1.1</junit.jupiter.version>
+ <junit.vintage.version>5.1.1</junit.vintage.version>
+ <junit.platform.version>1.1.1</junit.platform.version>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-surefire-provider</artifactId>
+ <version>${junit.platform.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <version>${junit.jupiter.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>junit5-vintage</id>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <junit.platform.version>1.1.1</junit.platform.version>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-surefire-provider</artifactId>
+ <version>${junit.platform.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ <version>${junit.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
</project>
diff --git a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java b/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
index e9234f2..144df74 100644
--- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
+++ b/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
@@ -25,14 +25,12 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-
public class BasicTest
{
+ private static boolean tearDownCalled = false;
private boolean setUpCalled = false;
- private static boolean tearDownCalled = false;
-
@Before
public void setUp()
{
diff --git a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java b/surefire-its/src/test/resources/junit4/src/test/java/junit5/JUnit5Test.java
similarity index 66%
copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
copy to surefire-its/src/test/resources/junit4/src/test/java/junit5/JUnit5Test.java
index e9234f2..0dd000c 100644
--- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
+++ b/surefire-its/src/test/resources/junit4/src/test/java/junit5/JUnit5Test.java
@@ -1,4 +1,4 @@
-package junit4;
+package junit5;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,32 +19,32 @@ package junit4;
* under the License.
*/
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertTrue;
-public class BasicTest
+/**
+ * A test using the JUnit 5 API, which should be executed by JUnit jupiter enigne
+ */
+public class JUnit5Test
{
+ private static boolean tearDownCalled;
- private boolean setUpCalled = false;
+ private boolean setUpCalled;
- private static boolean tearDownCalled = false;
-
- @Before
+ @BeforeEach
public void setUp()
{
setUpCalled = true;
- tearDownCalled = false;
System.out.println( "Called setUp" );
}
- @After
+ @AfterEach
public void tearDown()
{
- setUpCalled = false;
tearDownCalled = true;
System.out.println( "Called tearDown" );
}
@@ -52,14 +52,13 @@ public class BasicTest
@Test
public void testSetUp()
{
- Assert.assertTrue( "setUp was not called", setUpCalled );
+ assertTrue( setUpCalled, "setUp was not called" );
}
-
- @AfterClass
+ @AfterAll
public static void oneTimeTearDown()
{
-
+ assertTrue( tearDownCalled, "tearDown was not called" );
}
}
diff --git a/surefire-its/src/test/resources/junit5/pom.xml b/surefire-its/src/test/resources/junit5/pom.xml
new file mode 100644
index 0000000..b44c2cc
--- /dev/null
+++ b/surefire-its/src/test/resources/junit5/pom.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.plugins.surefire</groupId>
+ <artifactId>junit5</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <name>Test for JUnit 5</name>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <java.version>1.8</java.version>
+ <junit.jupiter.version>5.1.1</junit.jupiter.version>
+ <junit.vintage.version>5.1.1</junit.vintage.version>
+ <junit.platform.version>1.1.1</junit.platform.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <version>${junit.jupiter.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ <version>${junit.vintage.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire.version}</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-surefire-provider</artifactId>
+ <version>${junit.platform.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java b/surefire-its/src/test/resources/junit5/src/test/java/junit5/JUnit4Test.java
similarity index 83%
copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
copy to surefire-its/src/test/resources/junit5/src/test/java/junit5/JUnit4Test.java
index e9234f2..0a94b1a 100644
--- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
+++ b/surefire-its/src/test/resources/junit5/src/test/java/junit5/JUnit4Test.java
@@ -1,4 +1,4 @@
-package junit4;
+package junit5;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -25,26 +25,26 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-
-public class BasicTest
+/**
+ * A test using the JUnit 4 API, which should be executed by JUnit vintage enigne
+ */
+public class JUnit4Test
{
- private boolean setUpCalled = false;
+ private boolean setUpCalled;
+
+ private static boolean tearDownCalled;
- private static boolean tearDownCalled = false;
-
@Before
public void setUp()
{
setUpCalled = true;
- tearDownCalled = false;
System.out.println( "Called setUp" );
}
@After
public void tearDown()
{
- setUpCalled = false;
tearDownCalled = true;
System.out.println( "Called tearDown" );
}
@@ -54,12 +54,11 @@ public class BasicTest
{
Assert.assertTrue( "setUp was not called", setUpCalled );
}
-
@AfterClass
public static void oneTimeTearDown()
{
-
+ Assert.assertTrue( "tearDown was not called", tearDownCalled );
}
}
diff --git a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java b/surefire-its/src/test/resources/junit5/src/test/java/junit5/JUnit5Test.java
similarity index 66%
copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
copy to surefire-its/src/test/resources/junit5/src/test/java/junit5/JUnit5Test.java
index e9234f2..558546d 100644
--- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java
+++ b/surefire-its/src/test/resources/junit5/src/test/java/junit5/JUnit5Test.java
@@ -1,4 +1,4 @@
-package junit4;
+package junit5;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -19,32 +19,33 @@ package junit4;
* under the License.
*/
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
-public class BasicTest
+/**
+ * A test using the JUnit 5 API, which should be executed by JUnit jupiter enigne
+ */
+public class JUnit5Test
{
- private boolean setUpCalled = false;
+ private boolean setUpCalled;
+
+ private static boolean tearDownCalled;
- private static boolean tearDownCalled = false;
-
- @Before
+ @BeforeEach
public void setUp()
{
setUpCalled = true;
- tearDownCalled = false;
System.out.println( "Called setUp" );
}
- @After
+ @AfterEach
public void tearDown()
{
- setUpCalled = false;
tearDownCalled = true;
System.out.println( "Called tearDown" );
}
@@ -52,14 +53,13 @@ public class BasicTest
@Test
public void testSetUp()
{
- Assert.assertTrue( "setUp was not called", setUpCalled );
+ Assertions.assertTrue( setUpCalled, "setUp was not called" );
}
-
- @AfterClass
+ @AfterAll
public static void oneTimeTearDown()
{
-
+ Assertions.assertTrue( tearDownCalled, "tearDown was not called" );
}
}
diff --git a/surefire-providers/pom.xml b/surefire-providers/pom.xml
index 0322bcc..47b0f40 100644
--- a/surefire-providers/pom.xml
+++ b/surefire-providers/pom.xml
@@ -41,6 +41,7 @@
<module>surefire-junit3</module>
<module>surefire-junit4</module>
<module>surefire-junit47</module>
+ <module>surefire-junit-platform</module>
<module>surefire-testng-utils</module>
<module>surefire-testng</module>
</modules>
diff --git a/surefire-providers/surefire-junit-platform/pom.xml b/surefire-providers/surefire-junit-platform/pom.xml
new file mode 100644
index 0000000..bf4869b
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/pom.xml
@@ -0,0 +1,161 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-providers</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>surefire-junit-platform</artifactId>
+ <name>SureFire JUnit Platform Runner</name>
+ <description>SureFire JUnit Platform Runner</description>
+ <properties>
+ <javaVersion>8</javaVersion>
+ </properties>
+ <contributors>
+ <contributor>
+ <name>Konstantin Lutovich</name>
+ <roles>
+ <role>Contributed to the original provider implementation</role>
+ </roles>
+ </contributor>
+ <contributor>
+ <name>Shintaro Katafuchi</name>
+ <roles>
+ <role>Contributed to the original provider implementation</role>
+ </roles>
+ </contributor>
+ <contributor>
+ <name>Sam Brannen</name>
+ <roles>
+ <role>Contributed to the original provider implementation</role>
+ </roles>
+ </contributor>
+ <contributor>
+ <name>Stefan Bechtold</name>
+ <roles>
+ <role>Contributed to the original provider implementation</role>
+ </roles>
+ </contributor>
+ <contributor>
+ <name>Marc Philipp</name>
+ <roles>
+ <role>Contributed to the original provider implementation</role>
+ </roles>
+ </contributor>
+ <contributor>
+ <name>Matthias Merdes</name>
+ <roles>
+ <role>Contributed to the original provider implementation</role>
+ </roles>
+ </contributor>
+ <contributor>
+ <name>Johannes Link</name>
+ <roles>
+ <role>Contributed to the original provider implementation</role>
+ </roles>
+ </contributor>
+ </contributors>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>common-java5</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-launcher</artifactId>
+ <version>1.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <version>5.2.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <version>3.6.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>animal-sniffer-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>signature-check</id>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ <configuration>
+ <signature combine.self="override">
+ <groupId>org.codehaus.mojo.signature</groupId>
+ <artifactId>java18</artifactId>
+ <version>1.0</version>
+ </signature>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <jvm>${java.home}/bin/java</jvm>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <artifactSet>
+ <includes>
+ <include>org.apache.maven.surefire:common-java5</include>
+ </includes>
+ </artifactSet>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java
new file mode 100644
index 0000000..510266e
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java
@@ -0,0 +1,241 @@
+package org.apache.maven.surefire.junitplatform;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import static java.util.Collections.emptyMap;
+import static java.util.stream.Collectors.toList;
+import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
+import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.maven.surefire.providerapi.AbstractProvider;
+import org.apache.maven.surefire.providerapi.ProviderParameters;
+import org.apache.maven.surefire.report.ConsoleOutputCapture;
+import org.apache.maven.surefire.report.ConsoleOutputReceiver;
+import org.apache.maven.surefire.report.ReporterException;
+import org.apache.maven.surefire.report.ReporterFactory;
+import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.suite.RunResult;
+import org.apache.maven.surefire.testset.TestListResolver;
+import org.apache.maven.surefire.testset.TestSetFailedException;
+import org.apache.maven.surefire.util.ScanResult;
+import org.apache.maven.surefire.util.TestsToRun;
+import org.junit.platform.commons.util.Preconditions;
+import org.junit.platform.commons.util.StringUtils;
+import org.junit.platform.engine.Filter;
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.LauncherDiscoveryRequest;
+import org.junit.platform.launcher.TagFilter;
+import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
+import org.junit.platform.launcher.core.LauncherFactory;
+
+public class JUnitPlatformProvider
+ extends AbstractProvider
+{
+
+ // Parameter names processed to determine which @Tags should be executed.
+ static final String EXCLUDE_GROUPS = "excludedGroups";
+
+ static final String EXCLUDE_TAGS = "excludeTags";
+
+ static final String INCLUDE_GROUPS = "groups";
+
+ static final String INCLUDE_TAGS = "includeTags";
+
+ static final String CONFIGURATION_PARAMETERS = "configurationParameters";
+
+ static final String EXCEPTION_MESSAGE_BOTH_NOT_ALLOWED = "The " + INCLUDE_GROUPS + " and " + INCLUDE_TAGS
+ + " parameters (or the " + EXCLUDE_GROUPS + " and " + EXCLUDE_TAGS + " parameters) are synonyms - "
+ + "only one of each is allowed (though neither is required).";
+
+ private final ProviderParameters parameters;
+
+ private final Launcher launcher;
+
+ final Filter<?>[] filters;
+
+ final Map<String, String> configurationParameters;
+
+ JUnitPlatformProvider( ProviderParameters parameters )
+ {
+ this( parameters, LauncherFactory.create() );
+ }
+
+ JUnitPlatformProvider( ProviderParameters parameters, Launcher launcher )
+ {
+ this.parameters = parameters;
+ this.launcher = launcher;
+ this.filters = getFilters();
+ this.configurationParameters = getConfigurationParameters();
+ Logger.getLogger( "org.junit" ).setLevel( Level.WARNING );
+ }
+
+ @Override
+ public Iterable<Class<?>> getSuites()
+ {
+ return scanClasspath();
+ }
+
+ @Override
+ public RunResult invoke( Object forkTestSet )
+ throws TestSetFailedException, ReporterException
+ {
+ if ( forkTestSet instanceof TestsToRun )
+ {
+ return invokeAllTests( (TestsToRun) forkTestSet );
+ }
+ else if ( forkTestSet instanceof Class )
+ {
+ return invokeAllTests( TestsToRun.fromClass( (Class<?>) forkTestSet ) );
+ }
+ else if ( forkTestSet == null )
+ {
+ return invokeAllTests( scanClasspath() );
+ }
+ else
+ {
+ throw new IllegalArgumentException( "Unexpected value of forkTestSet: " + forkTestSet );
+ }
+ }
+
+ private TestsToRun scanClasspath()
+ {
+ TestPlanScannerFilter filter = new TestPlanScannerFilter( launcher, filters );
+ ScanResult scanResult = parameters.getScanResult();
+ TestsToRun scannedClasses = scanResult.applyFilter( filter, parameters.getTestClassLoader() );
+ return parameters.getRunOrderCalculator().orderTestClasses( scannedClasses );
+ }
+
+ private RunResult invokeAllTests( TestsToRun testsToRun )
+ {
+ RunResult runResult;
+ ReporterFactory reporterFactory = parameters.getReporterFactory();
+ try
+ {
+ RunListener runListener = reporterFactory.createReporter();
+ ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) runListener );
+ LauncherDiscoveryRequest discoveryRequest = buildLauncherDiscoveryRequest( testsToRun );
+ launcher.execute( discoveryRequest, new RunListenerAdapter( runListener ) );
+ }
+ finally
+ {
+ runResult = reporterFactory.close();
+ }
+ return runResult;
+ }
+
+ private LauncherDiscoveryRequest buildLauncherDiscoveryRequest( TestsToRun testsToRun )
+ {
+ LauncherDiscoveryRequestBuilder builder =
+ request().filters( filters ).configurationParameters( configurationParameters );
+ for ( Class<?> testClass : testsToRun )
+ {
+ builder.selectors( selectClass( testClass ) );
+ }
+ return builder.build();
+ }
+
+ private Filter<?>[] getFilters()
+ {
+ List<Filter<?>> filters = new ArrayList<>();
+
+ Optional<List<String>> includes =
+ getGroupsOrTags( getPropertiesList( INCLUDE_GROUPS ), getPropertiesList( INCLUDE_TAGS ) );
+ includes.map( TagFilter::includeTags ).ifPresent( filters::add );
+
+ Optional<List<String>> excludes =
+ getGroupsOrTags( getPropertiesList( EXCLUDE_GROUPS ), getPropertiesList( EXCLUDE_TAGS ) );
+ excludes.map( TagFilter::excludeTags ).ifPresent( filters::add );
+
+ TestListResolver testListResolver = parameters.getTestRequest().getTestListResolver();
+ if ( !testListResolver.isEmpty() )
+ {
+ filters.add( new TestMethodFilter( testListResolver ) );
+ }
+
+ return filters.toArray( new Filter<?>[0] );
+ }
+
+ private Map<String, String> getConfigurationParameters()
+ {
+ String content = parameters.getProviderProperties().get( CONFIGURATION_PARAMETERS );
+ if ( content == null )
+ {
+ return emptyMap();
+ }
+ try ( StringReader reader = new StringReader( content ) )
+ {
+ Map<String, String> result = new HashMap<>();
+ Properties props = new Properties();
+ props.load( reader );
+ props.stringPropertyNames().forEach( key -> result.put( key, props.getProperty( key ) ) );
+ return result;
+ }
+ catch ( IOException ex )
+ {
+ throw new UncheckedIOException( "Error reading " + CONFIGURATION_PARAMETERS, ex );
+ }
+ }
+
+ private Optional<List<String>> getPropertiesList( String key )
+ {
+ List<String> compoundProperties = null;
+ String property = parameters.getProviderProperties().get( key );
+ if ( StringUtils.isNotBlank( property ) )
+ {
+ compoundProperties =
+ Arrays.stream( property.split( "[,]+" ) )
+ .filter( StringUtils::isNotBlank )
+ .map( String::trim )
+ .collect( toList() );
+ }
+ return Optional.ofNullable( compoundProperties );
+ }
+
+ private Optional<List<String>> getGroupsOrTags( Optional<List<String>> groups, Optional<List<String>> tags )
+ {
+ Optional<List<String>> elements = Optional.empty();
+
+ Preconditions.condition(!groups.isPresent() || !tags.isPresent(), EXCEPTION_MESSAGE_BOTH_NOT_ALLOWED );
+
+ if ( groups.isPresent() )
+ {
+ elements = groups;
+ }
+ else if ( tags.isPresent() )
+ {
+ elements = tags;
+ }
+
+ return elements;
+ }
+}
diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java
new file mode 100644
index 0000000..71a70c3
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java
@@ -0,0 +1,272 @@
+package org.apache.maven.surefire.junitplatform;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.apache.maven.surefire.report.SimpleReportEntry.ignored;
+import static org.junit.platform.engine.TestExecutionResult.Status.ABORTED;
+import static org.junit.platform.engine.TestExecutionResult.Status.FAILED;
+
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.maven.surefire.report.PojoStackTraceWriter;
+import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.SimpleReportEntry;
+import org.apache.maven.surefire.report.StackTraceWriter;
+import org.junit.platform.engine.TestExecutionResult;
+import org.junit.platform.engine.TestSource;
+import org.junit.platform.engine.support.descriptor.ClassSource;
+import org.junit.platform.engine.support.descriptor.MethodSource;
+import org.junit.platform.launcher.TestExecutionListener;
+import org.junit.platform.launcher.TestIdentifier;
+import org.junit.platform.launcher.TestPlan;
+import org.junit.platform.launcher.listeners.LegacyReportingUtils;
+
+/**
+ * @since 1.0
+ */
+final class RunListenerAdapter
+ implements TestExecutionListener
+{
+
+ private final RunListener runListener;
+
+ private TestPlan testPlan;
+
+ private Set<TestIdentifier> testSetNodes = ConcurrentHashMap.newKeySet();
+
+ RunListenerAdapter( RunListener runListener )
+ {
+ this.runListener = runListener;
+ }
+
+ @Override
+ public void testPlanExecutionStarted( TestPlan testPlan )
+ {
+ updateTestPlan( testPlan );
+ }
+
+ @Override
+ public void testPlanExecutionFinished( TestPlan testPlan )
+ {
+ updateTestPlan( null );
+ }
+
+ @Override
+ public void executionStarted( TestIdentifier testIdentifier )
+ {
+ if ( testIdentifier.isContainer()
+ && testIdentifier.getSource().filter( ClassSource.class::isInstance ).isPresent() )
+ {
+ startTestSetIfPossible( testIdentifier );
+ }
+ if ( testIdentifier.isTest() )
+ {
+ ensureTestSetStarted( testIdentifier );
+ runListener.testStarting( createReportEntry( testIdentifier ) );
+ }
+ }
+
+ @Override
+ public void executionSkipped( TestIdentifier testIdentifier, String reason )
+ {
+ ensureTestSetStarted( testIdentifier );
+ String source = getLegacyReportingClassName( testIdentifier );
+ runListener.testSkipped( ignored( source, getLegacyReportingName( testIdentifier ), reason ) );
+ completeTestSetIfNecessary( testIdentifier );
+ }
+
+ @Override
+ public void executionFinished(
+ TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
+ {
+ if ( testExecutionResult.getStatus() == ABORTED )
+ {
+ runListener.testAssumptionFailure( createReportEntry( testIdentifier, testExecutionResult ) );
+ }
+ else if ( testExecutionResult.getStatus() == FAILED )
+ {
+ reportFailedTest( testIdentifier, testExecutionResult );
+ }
+ else if ( testIdentifier.isTest() )
+ {
+ runListener.testSucceeded( createReportEntry( testIdentifier ) );
+ }
+ completeTestSetIfNecessary( testIdentifier );
+ }
+
+ private void updateTestPlan( TestPlan testPlan )
+ {
+ this.testPlan = testPlan;
+ testSetNodes.clear();
+ }
+
+ private void ensureTestSetStarted( TestIdentifier testIdentifier )
+ {
+ if ( isTestSetStarted( testIdentifier ) )
+ {
+ return;
+ }
+ if ( testIdentifier.isTest() )
+ {
+ startTestSet( testPlan.getParent( testIdentifier ).orElse( testIdentifier ) );
+ }
+ else
+ {
+ startTestSet( testIdentifier );
+ }
+ }
+
+ private boolean isTestSetStarted( TestIdentifier testIdentifier )
+ {
+ return testSetNodes.contains( testIdentifier )
+ || testPlan.getParent( testIdentifier ).map( this::isTestSetStarted ).orElse( false );
+ }
+
+ private void startTestSetIfPossible( TestIdentifier testIdentifier )
+ {
+ if ( !isTestSetStarted( testIdentifier ) )
+ {
+ startTestSet( testIdentifier );
+ }
+ }
+
+ private void completeTestSetIfNecessary( TestIdentifier testIdentifier )
+ {
+ if ( testSetNodes.contains( testIdentifier ) )
+ {
+ completeTestSet( testIdentifier );
+ }
+ }
+
+ private void startTestSet( TestIdentifier testIdentifier )
+ {
+ runListener.testSetStarting( createTestSetReportEntry( testIdentifier ) );
+ testSetNodes.add( testIdentifier );
+ }
+
+ private void completeTestSet( TestIdentifier testIdentifier )
+ {
+ runListener.testSetCompleted( createTestSetReportEntry( testIdentifier ) );
+ testSetNodes.remove( testIdentifier );
+ }
+
+ private void reportFailedTest(
+ TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
+ {
+ SimpleReportEntry reportEntry = createReportEntry( testIdentifier, testExecutionResult );
+ if ( testExecutionResult.getThrowable().filter( AssertionError.class::isInstance ).isPresent() )
+ {
+ runListener.testFailed( reportEntry );
+ }
+ else
+ {
+ runListener.testError( reportEntry );
+ }
+ }
+
+ private SimpleReportEntry createTestSetReportEntry( TestIdentifier testIdentifier )
+ {
+ return new SimpleReportEntry(
+ JUnitPlatformProvider.class.getName(), testIdentifier.getLegacyReportingName() );
+ }
+
+ private SimpleReportEntry createReportEntry( TestIdentifier testIdentifier )
+ {
+ return createReportEntry( testIdentifier, (StackTraceWriter) null );
+ }
+
+ private SimpleReportEntry createReportEntry(
+ TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
+ {
+ return createReportEntry(
+ testIdentifier, getStackTraceWriter( testIdentifier, testExecutionResult ) );
+ }
+
+ private SimpleReportEntry createReportEntry(
+ TestIdentifier testIdentifier, StackTraceWriter stackTraceWriter )
+ {
+ String source = getLegacyReportingClassName( testIdentifier );
+ String name = getLegacyReportingName( testIdentifier );
+
+ return SimpleReportEntry.withException( source, name, stackTraceWriter );
+ }
+
+ private String getLegacyReportingName( TestIdentifier testIdentifier )
+ {
+ // Surefire cuts off the name at the first '(' character. Thus, we have to pick a different
+ // character to represent parentheses. "()" are removed entirely to maximize compatibility with
+ // existing reporting tools because in the old days test methods used to not have parameters.
+ return testIdentifier
+ .getLegacyReportingName()
+ .replace( "()", "" )
+ .replace( '(', '{' )
+ .replace( ')', '}' );
+ }
+
+ private String getLegacyReportingClassName( TestIdentifier testIdentifier )
+ {
+ return LegacyReportingUtils.getClassName( testPlan, testIdentifier );
+ }
+
+ private StackTraceWriter getStackTraceWriter(
+ TestIdentifier testIdentifier, TestExecutionResult testExecutionResult )
+ {
+ Optional<Throwable> throwable = testExecutionResult.getThrowable();
+ if ( testExecutionResult.getStatus() == FAILED )
+ {
+ // Failed tests must have a StackTraceWriter, otherwise Surefire will fail
+ return getStackTraceWriter( testIdentifier, throwable.orElse( null ) );
+ }
+ return throwable.map( t -> getStackTraceWriter( testIdentifier, t ) ).orElse( null );
+ }
+
+ private StackTraceWriter getStackTraceWriter( TestIdentifier testIdentifier, Throwable throwable )
+ {
+ String className = getClassName( testIdentifier );
+ String methodName = getMethodName( testIdentifier ).orElse( "" );
+ return new PojoStackTraceWriter( className, methodName, throwable );
+ }
+
+ private String getClassName( TestIdentifier testIdentifier )
+ {
+ TestSource testSource = testIdentifier.getSource().orElse( null );
+ if ( testSource instanceof ClassSource )
+ {
+ return ( (ClassSource) testSource ).getJavaClass().getName();
+ }
+ if ( testSource instanceof MethodSource )
+ {
+ return ( (MethodSource) testSource ).getClassName();
+ }
+ return testPlan.getParent( testIdentifier ).map( this::getClassName ).orElse( "" );
+ }
+
+ private Optional<String> getMethodName( TestIdentifier testIdentifier )
+ {
+ TestSource testSource = testIdentifier.getSource().orElse( null );
+ if ( testSource instanceof MethodSource )
+ {
+ return Optional.of( ( (MethodSource) testSource ).getMethodName() );
+ }
+ return Optional.empty();
+ }
+}
diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestMethodFilter.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestMethodFilter.java
new file mode 100644
index 0000000..45e32db
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestMethodFilter.java
@@ -0,0 +1,60 @@
+package org.apache.maven.surefire.junitplatform;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.maven.surefire.testset.TestListResolver;
+import org.junit.platform.engine.FilterResult;
+import org.junit.platform.engine.TestDescriptor;
+import org.junit.platform.engine.support.descriptor.MethodSource;
+import org.junit.platform.launcher.PostDiscoveryFilter;
+
+/**
+ * @since 1.0.3
+ */
+class TestMethodFilter
+ implements PostDiscoveryFilter
+{
+
+ private final TestListResolver testListResolver;
+
+ TestMethodFilter( TestListResolver testListResolver )
+ {
+ this.testListResolver = testListResolver;
+ }
+
+ @Override
+ public FilterResult apply( TestDescriptor descriptor )
+ {
+ boolean shouldRun = descriptor.getSource()
+ .filter( MethodSource.class::isInstance )
+ .map( MethodSource.class::cast )
+ .map( this::shouldRun )
+ .orElse( true );
+
+ return FilterResult.includedIf( shouldRun );
+ }
+
+ private boolean shouldRun( MethodSource source )
+ {
+ String testClass = TestListResolver.toClassFileName( source.getClassName() );
+ String testMethod = source.getMethodName();
+ return this.testListResolver.shouldRun( testClass, testMethod );
+ }
+}
diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestPlanScannerFilter.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestPlanScannerFilter.java
new file mode 100644
index 0000000..4b488c1
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/TestPlanScannerFilter.java
@@ -0,0 +1,60 @@
+package org.apache.maven.surefire.junitplatform;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
+import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
+
+import org.apache.maven.surefire.util.ScannerFilter;
+import org.junit.platform.engine.Filter;
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.LauncherDiscoveryRequest;
+import org.junit.platform.launcher.TestPlan;
+
+/**
+ * @since 1.0
+ */
+final class TestPlanScannerFilter
+ implements ScannerFilter
+{
+
+ private final Launcher launcher;
+
+ private final Filter<?>[] includeAndExcludeFilters;
+
+ TestPlanScannerFilter( Launcher launcher, Filter<?>[] includeAndExcludeFilters )
+ {
+ this.launcher = launcher;
+ this.includeAndExcludeFilters = includeAndExcludeFilters;
+ }
+
+ @Override
+ @SuppressWarnings( "rawtypes" )
+ public boolean accept( Class testClass )
+ {
+ LauncherDiscoveryRequest discoveryRequest = request()
+ .selectors( selectClass( testClass ) )
+ .filters( includeAndExcludeFilters ).build();
+
+ TestPlan testPlan = launcher.discover( discoveryRequest );
+
+ return testPlan.containsTests();
+ }
+}
diff --git a/surefire-providers/surefire-junit-platform/src/main/resources/META-INF/services/org.apache.maven.surefire.providerapi.SurefireProvider b/surefire-providers/surefire-junit-platform/src/main/resources/META-INF/services/org.apache.maven.surefire.providerapi.SurefireProvider
new file mode 100644
index 0000000..dbe73cf
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/src/main/resources/META-INF/services/org.apache.maven.surefire.providerapi.SurefireProvider
@@ -0,0 +1 @@
+org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProviderTests.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProviderTests.java
new file mode 100644
index 0000000..e0db97e
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProviderTests.java
@@ -0,0 +1,756 @@
+package org.apache.maven.surefire.junitplatform;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.singletonMap;
+import static java.util.stream.Collectors.toSet;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+import static org.mockito.AdditionalMatchers.gt;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.surefire.providerapi.ProviderParameters;
+import org.apache.maven.surefire.report.ConsoleOutputReceiver;
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.ReporterFactory;
+import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.SimpleReportEntry;
+import org.apache.maven.surefire.testset.TestListResolver;
+import org.apache.maven.surefire.testset.TestRequest;
+import org.apache.maven.surefire.testset.TestSetFailedException;
+import org.apache.maven.surefire.util.RunOrderCalculator;
+import org.apache.maven.surefire.util.ScanResult;
+import org.apache.maven.surefire.util.TestsToRun;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.platform.commons.util.PreconditionViolationException;
+import org.junit.platform.launcher.Launcher;
+import org.junit.platform.launcher.TestIdentifier;
+import org.junit.platform.launcher.TestPlan;
+import org.junit.platform.launcher.core.LauncherFactory;
+import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
+import org.junit.platform.launcher.listeners.TestExecutionSummary;
+import org.junit.platform.launcher.listeners.TestExecutionSummary.Failure;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+
+/**
+ * Unit tests for {@link JUnitPlatformProvider}.
+ *
+ * @since 1.0
+ */
+class JUnitPlatformProviderTests
+{
+
+ @Test
+ void getSuitesReturnsScannedClasses()
+ throws Exception
+ {
+ ProviderParameters providerParameters =
+ providerParametersMock( TestClass1.class, TestClass2.class );
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertThat( provider.getSuites() ).containsOnly( TestClass1.class, TestClass2.class );
+ }
+
+ @Test
+ void invokeThrowsForWrongForkTestSet()
+ throws Exception
+ {
+ ProviderParameters providerParameters = providerParametersMock( Integer.class );
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertThrows(
+ IllegalArgumentException.class, () -> invokeProvider( provider, "wrong forkTestSet" ) );
+ }
+
+ @Test
+ void allGivenTestsToRunAreInvoked()
+ throws Exception
+ {
+ Launcher launcher = LauncherFactory.create();
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParametersMock(), launcher );
+
+ TestPlanSummaryListener executionListener = new TestPlanSummaryListener();
+ launcher.registerTestExecutionListeners( executionListener );
+
+ TestsToRun testsToRun = newTestsToRun( TestClass1.class, TestClass2.class );
+ invokeProvider( provider, testsToRun );
+
+ assertThat( executionListener.summaries ).hasSize( 1 );
+ TestExecutionSummary summary = executionListener.summaries.get( 0 );
+ assertEquals( TestClass1.TESTS_FOUND + TestClass2.TESTS_FOUND, summary.getTestsFoundCount() );
+ assertEquals(
+ TestClass1.TESTS_STARTED + TestClass2.TESTS_STARTED, summary.getTestsStartedCount() );
+ assertEquals(
+ TestClass1.TESTS_SKIPPED + TestClass2.TESTS_SKIPPED, summary.getTestsSkippedCount() );
+ assertEquals(
+ TestClass1.TESTS_SUCCEEDED + TestClass2.TESTS_SUCCEEDED, summary.getTestsSucceededCount() );
+ assertEquals(
+ TestClass1.TESTS_ABORTED + TestClass2.TESTS_ABORTED, summary.getTestsAbortedCount() );
+ assertEquals( TestClass1.TESTS_FAILED + TestClass2.TESTS_FAILED, summary.getTestsFailedCount() );
+ }
+
+ @Test
+ void singleTestClassIsInvoked()
+ throws Exception
+ {
+ Launcher launcher = LauncherFactory.create();
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParametersMock(), launcher );
+
+ TestPlanSummaryListener executionListener = new TestPlanSummaryListener();
+ launcher.registerTestExecutionListeners( executionListener );
+
+ invokeProvider( provider, TestClass1.class );
+
+ assertThat( executionListener.summaries ).hasSize( 1 );
+ TestExecutionSummary summary = executionListener.summaries.get( 0 );
+ assertEquals( TestClass1.TESTS_FOUND, summary.getTestsFoundCount() );
+ assertEquals( TestClass1.TESTS_STARTED, summary.getTestsStartedCount() );
+ assertEquals( TestClass1.TESTS_SKIPPED, summary.getTestsSkippedCount() );
+ assertEquals( TestClass1.TESTS_SUCCEEDED, summary.getTestsSucceededCount() );
+ assertEquals( TestClass1.TESTS_ABORTED, summary.getTestsAbortedCount() );
+ assertEquals( TestClass1.TESTS_FAILED, summary.getTestsFailedCount() );
+ }
+
+ @Test
+ void allDiscoveredTestsAreInvokedForNullArgument()
+ throws Exception
+ {
+ RunListener runListener = runListenerMock();
+ ProviderParameters providerParameters =
+ providerParametersMock( runListener, TestClass1.class, TestClass2.class );
+ Launcher launcher = LauncherFactory.create();
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters, launcher );
+
+ TestPlanSummaryListener executionListener = new TestPlanSummaryListener();
+ launcher.registerTestExecutionListeners( executionListener );
+
+ invokeProvider( provider, null );
+
+ InOrder inOrder = inOrder( runListener );
+ inOrder
+ .verify( runListener )
+ .testSetStarting(
+ new SimpleReportEntry(
+ JUnitPlatformProvider.class.getName(),
+ TestClass1.class.getName() ) );
+ inOrder
+ .verify( runListener )
+ .testSetCompleted(
+ new SimpleReportEntry(
+ JUnitPlatformProvider.class.getName(),
+ TestClass1.class.getName() ) );
+ inOrder
+ .verify( runListener )
+ .testSetStarting(
+ new SimpleReportEntry(
+ JUnitPlatformProvider.class.getName(),
+ TestClass2.class.getName() ) );
+ inOrder
+ .verify( runListener )
+ .testSetCompleted(
+ new SimpleReportEntry(
+ JUnitPlatformProvider.class.getName(),
+ TestClass2.class.getName() ) );
+
+ assertThat( executionListener.summaries ).hasSize( 1 );
+ TestExecutionSummary summary = executionListener.summaries.get( 0 );
+ assertEquals( TestClass1.TESTS_FOUND + TestClass2.TESTS_FOUND, summary.getTestsFoundCount() );
+ assertEquals(
+ TestClass1.TESTS_STARTED + TestClass2.TESTS_STARTED, summary.getTestsStartedCount() );
+ assertEquals(
+ TestClass1.TESTS_SKIPPED + TestClass2.TESTS_SKIPPED, summary.getTestsSkippedCount() );
+ assertEquals(
+ TestClass1.TESTS_SUCCEEDED + TestClass2.TESTS_SUCCEEDED, summary.getTestsSucceededCount() );
+ assertEquals(
+ TestClass1.TESTS_ABORTED + TestClass2.TESTS_ABORTED, summary.getTestsAbortedCount() );
+ assertEquals( TestClass1.TESTS_FAILED + TestClass2.TESTS_FAILED, summary.getTestsFailedCount() );
+ }
+
+ @Test
+ void outputIsCaptured()
+ throws Exception
+ {
+ Launcher launcher = LauncherFactory.create();
+ RunListener runListener = runListenerMock();
+ JUnitPlatformProvider provider =
+ new JUnitPlatformProvider( providerParametersMock( runListener ), launcher );
+
+ invokeProvider( provider, VerboseTestClass.class );
+
+ ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass( byte[].class );
+ // @formatter:off
+ verify( (ConsoleOutputReceiver) runListener )
+ .writeTestOutput( captor.capture(), eq( 0 ), gt( 6 ), eq( true ) );
+ verify( (ConsoleOutputReceiver) runListener )
+ .writeTestOutput( captor.capture(), eq( 0 ), gt( 6 ), eq( false ) );
+ assertThat( captor.getAllValues() )
+ .extracting( bytes -> new String( bytes, 0, 6 ) )
+ .containsExactly( "stdout", "stderr" );
+ // @formatter:on
+ }
+
+ @Test
+ void bothGroupsAndIncludeTagsThrowsException()
+ {
+ Map<String, String> properties = new HashMap<>();
+ properties.put( JUnitPlatformProvider.INCLUDE_GROUPS, "groupOne, groupTwo" );
+ properties.put( JUnitPlatformProvider.INCLUDE_TAGS, "tagOne, tagTwo" );
+ verifyPreconditionViolationException( properties );
+ }
+
+ @Test
+ void bothExcludedGroupsAndExcludeTagsThrowsException()
+ {
+ Map<String, String> properties = new HashMap<>();
+ properties.put( JUnitPlatformProvider.EXCLUDE_GROUPS, "groupOne, groupTwo" );
+ properties.put( JUnitPlatformProvider.EXCLUDE_TAGS, "tagOne, tagTwo" );
+ verifyPreconditionViolationException( properties );
+ }
+
+ @Test
+ void onlyGroupsIsDeclared()
+ throws Exception
+ {
+ Map<String, String> properties = new HashMap<>();
+ properties.put( JUnitPlatformProvider.INCLUDE_GROUPS, "groupOne, groupTwo" );
+
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() ).thenReturn( properties );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertEquals( 1, provider.filters.length );
+ }
+
+ @Test
+ void onlyExcludeTagsIsDeclared()
+ throws Exception
+ {
+ Map<String, String> properties = new HashMap<>();
+ properties.put( JUnitPlatformProvider.EXCLUDE_TAGS, "tagOne, tagTwo" );
+
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() ).thenReturn( properties );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertEquals( 1, provider.filters.length );
+ }
+
+ @Test
+ void noFiltersAreCreatedIfTagsAreEmpty()
+ throws Exception
+ {
+ Map<String, String> properties = new HashMap<>();
+ properties.put( JUnitPlatformProvider.INCLUDE_TAGS, "" );
+ properties.put( JUnitPlatformProvider.INCLUDE_GROUPS, "" );
+
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() ).thenReturn( properties );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+ assertEquals( 0, provider.filters.length );
+ }
+
+ @Test
+ void filtersWithEmptyTagsAreNotRegistered()
+ throws Exception
+ {
+ Map<String, String> properties = new HashMap<>();
+
+ // Here only tagOne is registered as a valid tag and other tags are ignored as they are empty
+ properties.put( JUnitPlatformProvider.EXCLUDE_GROUPS, "tagOne," );
+ properties.put( JUnitPlatformProvider.EXCLUDE_TAGS, "" );
+
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() ).thenReturn( properties );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+ assertEquals( 1, provider.filters.length );
+ }
+
+ @Test
+ void bothIncludeAndExcludeAreAllowed()
+ throws Exception
+ {
+ Map<String, String> properties = new HashMap<>();
+ properties.put( JUnitPlatformProvider.INCLUDE_TAGS, "tagOne, tagTwo" );
+ properties.put( JUnitPlatformProvider.EXCLUDE_TAGS, "tagThree, tagFour" );
+
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() ).thenReturn( properties );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertEquals( 2, provider.filters.length );
+ }
+
+ @Test
+ void tagExpressionsAreSupportedForIncludeTagsContainingVerticalBar()
+ {
+ Map<String, String> properties = new HashMap<>();
+ properties.put( JUnitPlatformProvider.INCLUDE_TAGS, "tagOne | tagTwo" );
+ properties.put( JUnitPlatformProvider.EXCLUDE_TAGS, "tagThree | tagFour" );
+
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() ).thenReturn( properties );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertEquals( 2, provider.filters.length );
+ }
+
+ @Test
+ void tagExpressionsAreSupportedForIncludeTagsContainingAmpersand()
+ {
+ Map<String, String> properties = new HashMap<>();
+ properties.put( JUnitPlatformProvider.INCLUDE_TAGS, "tagOne & !tagTwo" );
+ properties.put( JUnitPlatformProvider.EXCLUDE_TAGS, "tagThree & !tagFour" );
+
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() ).thenReturn( properties );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertEquals( 2, provider.filters.length );
+ }
+
+ @Test
+ void noFiltersAreCreatedIfNoPropertiesAreDeclared()
+ throws Exception
+ {
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertEquals( 0, provider.filters.length );
+ }
+
+ @Test
+ void defaultConfigurationParametersAreEmpty()
+ {
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() ).thenReturn( emptyMap() );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertTrue( provider.configurationParameters.isEmpty() );
+ }
+
+ @Test
+ void parsesConfigurationParameters()
+ {
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() )
+ .thenReturn( //
+ singletonMap(
+ JUnitPlatformProvider.CONFIGURATION_PARAMETERS,
+ "foo = true\nbar 42\rbaz: *\r\nqux: EOF" ) );
+
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters );
+
+ assertEquals( 4, provider.configurationParameters.size() );
+ assertEquals( "true", provider.configurationParameters.get( "foo" ) );
+ assertEquals( "42", provider.configurationParameters.get( "bar" ) );
+ assertEquals( "*", provider.configurationParameters.get( "baz" ) );
+ assertEquals( "EOF", provider.configurationParameters.get( "qux" ) );
+ }
+
+ @Test
+ void executesSingleTestIncludedByName()
+ throws Exception
+ {
+ // following is equivalent of adding '-Dtest=TestClass3#prefix1Suffix1'
+ // '*' needed because it's a nested class and thus has name prefixed with '$'
+ String pattern = "*TestClass3#prefix1Suffix1";
+
+ testExecutionOfMatchingTestMethods( TestClass3.class, pattern, "prefix1Suffix1()" );
+ }
+
+ @Test
+ void executesMultipleTestsIncludedByName()
+ throws Exception
+ {
+ // following is equivalent of adding '-Dtest=TestClass3#prefix1Suffix1+prefix2Suffix1'
+ // '*' needed because it's a nested class and thus has name prefixed with '$'
+ String pattern = "*TestClass3#prefix1Suffix1+prefix2Suffix1";
+
+ testExecutionOfMatchingTestMethods(
+ TestClass3.class, pattern, "prefix1Suffix1()", "prefix2Suffix1()" );
+ }
+
+ @Test
+ void executesMultipleTestsIncludedByNamePattern()
+ throws Exception
+ {
+ // following is equivalent of adding '-Dtest=TestClass3#prefix1*'
+ // '*' needed because it's a nested class and thus has name prefixed with '$'
+ String pattern = "*TestClass3#prefix1*";
+
+ testExecutionOfMatchingTestMethods(
+ TestClass3.class, pattern, "prefix1Suffix1()", "prefix1Suffix2()" );
+ }
+
+ @Test
+ void executesMultipleTestsIncludedByNamePatternWithQuestionMark()
+ throws Exception
+ {
+ // following is equivalent of adding '-Dtest=TestClass3#prefix?Suffix2'
+ // '*' needed because it's a nested class and thus has name prefixed with '$'
+ String pattern = "*TestClass3#prefix?Suffix2";
+
+ testExecutionOfMatchingTestMethods(
+ TestClass3.class, pattern, "prefix1Suffix2()", "prefix2Suffix2()" );
+ }
+
+ @Test
+ void doesNotExecuteTestsExcludedByName()
+ throws Exception
+ {
+ // following is equivalent of adding '-Dtest=!TestClass3#prefix1Suffix2'
+ // '*' needed because it's a nested class and thus has name prefixed with '$'
+ String pattern = "!*TestClass3#prefix1Suffix2";
+
+ testExecutionOfMatchingTestMethods(
+ TestClass3.class, pattern, "prefix1Suffix1()", "prefix2Suffix1()", "prefix2Suffix2()" );
+ }
+
+ @Test
+ void doesNotExecuteTestsExcludedByNamePattern()
+ throws Exception
+ {
+ // following is equivalent of adding '-Dtest=!TestClass3#prefix2*'
+ // '*' needed because it's a nested class and thus has name prefixed with '$'
+ String pattern = "!*TestClass3#prefix2*";
+
+ testExecutionOfMatchingTestMethods(
+ TestClass3.class, pattern, "prefix1Suffix1()", "prefix1Suffix2()" );
+ }
+
+ void testExecutionOfMatchingTestMethods(
+ Class<?> testClass, String pattern, String... expectedTestNames )
+ throws Exception
+ {
+ TestListResolver testListResolver = new TestListResolver( pattern );
+ ProviderParameters providerParameters = providerParametersMock( testListResolver, testClass );
+ Launcher launcher = LauncherFactory.create();
+ JUnitPlatformProvider provider = new JUnitPlatformProvider( providerParameters, launcher );
+
+ TestPlanSummaryListener executionListener = new TestPlanSummaryListener();
+ launcher.registerTestExecutionListeners( executionListener );
+
+ invokeProvider( provider, null );
+
+ assertEquals( 1, executionListener.summaries.size() );
+ TestExecutionSummary summary = executionListener.summaries.get( 0 );
+ int expectedCount = expectedTestNames.length;
+ assertEquals( expectedCount, summary.getTestsFoundCount() );
+ assertEquals( expectedCount, summary.getTestsFailedCount() );
+ assertEquals( expectedCount, summary.getFailures().size() );
+
+ assertThat( failedTestDisplayNames( summary ) ).contains( expectedTestNames );
+ }
+
+ private void verifyPreconditionViolationException( Map<String, String> properties )
+ {
+ ProviderParameters providerParameters = providerParametersMock( TestClass1.class );
+ when( providerParameters.getProviderProperties() ).thenReturn( properties );
+
+ Throwable throwable =
+ assertThrows(
+ PreconditionViolationException.class,
+ () -> new JUnitPlatformProvider( providerParameters ) );
+
+ assertEquals( JUnitPlatformProvider.EXCEPTION_MESSAGE_BOTH_NOT_ALLOWED, throwable.getMessage() );
+ }
+
+ private static ProviderParameters providerParametersMock( Class<?>... testClasses )
+ {
+ return providerParametersMock( runListenerMock(), testClasses );
+ }
+
+ private static ProviderParameters providerParametersMock(
+ RunListener runListener, Class<?>... testClasses )
+ {
+ TestListResolver testListResolver = new TestListResolver( "" );
+ return providerParametersMock( runListener, testListResolver, testClasses );
+ }
+
+ private static ProviderParameters providerParametersMock(
+ TestListResolver testListResolver, Class<?>... testClasses )
+ {
+ return providerParametersMock( runListenerMock(), testListResolver, testClasses );
+ }
+
+ private static ProviderParameters providerParametersMock(
+ RunListener runListener, TestListResolver testListResolver, Class<?>... testClasses )
+ {
+ TestsToRun testsToRun = newTestsToRun( testClasses );
+
+ ScanResult scanResult = mock( ScanResult.class );
+ when( scanResult.applyFilter( any(), any() ) ).thenReturn( testsToRun );
+
+ RunOrderCalculator runOrderCalculator = mock( RunOrderCalculator.class );
+ when( runOrderCalculator.orderTestClasses( any() ) ).thenReturn( testsToRun );
+
+ ReporterFactory reporterFactory = mock( ReporterFactory.class );
+ when( reporterFactory.createReporter() ).thenReturn( runListener );
+
+ TestRequest testRequest = mock( TestRequest.class );
+ when( testRequest.getTestListResolver() ).thenReturn( testListResolver );
+
+ ProviderParameters providerParameters = mock( ProviderParameters.class );
+ when( providerParameters.getScanResult() ).thenReturn( scanResult );
+ when( providerParameters.getRunOrderCalculator() ).thenReturn( runOrderCalculator );
+ when( providerParameters.getReporterFactory() ).thenReturn( reporterFactory );
+ when( providerParameters.getTestRequest() ).thenReturn( testRequest );
+
+ return providerParameters;
+ }
+
+ private static RunListener runListenerMock()
+ {
+ return mock( RunListener.class, withSettings().extraInterfaces( ConsoleOutputReceiver.class ) );
+ }
+
+ private static Set<String> failedTestDisplayNames( TestExecutionSummary summary )
+ {
+ // @formatter:off
+ return summary
+ .getFailures()
+ .stream()
+ .map( Failure::getTestIdentifier )
+ .map( TestIdentifier::getDisplayName )
+ .collect( toSet() );
+ // @formatter:on
+ }
+
+ private static TestsToRun newTestsToRun( Class<?>... testClasses )
+ {
+ List<Class<?>> classesList = Arrays.asList( testClasses );
+ return new TestsToRun( new LinkedHashSet<>( classesList ) );
+ }
+
+ private class TestPlanSummaryListener
+ extends SummaryGeneratingListener
+ {
+
+ final List<TestExecutionSummary> summaries = new ArrayList<>();
+
+ @Override
+ public void testPlanExecutionFinished( TestPlan testPlan )
+ {
+ super.testPlanExecutionFinished( testPlan );
+ summaries.add( getSummary() );
+ }
+ }
+
+ /**
+ * Invokes the provider, then restores system out and system error.
+ *
+ * @see <a href="https://github.com/junit-team/junit5/issues/986">#986</a>
+ */
+ private void invokeProvider( JUnitPlatformProvider provider, Object forkTestSet )
+ throws TestSetFailedException, InvocationTargetException
+ {
+ PrintStream systemOut = System.out;
+ PrintStream systemErr = System.err;
+ try
+ {
+ provider.invoke( forkTestSet );
+ }
+ finally
+ {
+ System.setOut( systemOut );
+ System.setErr( systemErr );
+ }
+ }
+
+ static class TestClass1
+ {
+
+ static final int TESTS_FOUND = 4;
+
+ static final int TESTS_STARTED = 3;
+
+ static final int TESTS_SKIPPED = 1;
+
+ static final int TESTS_SUCCEEDED = 2;
+
+ static final int TESTS_ABORTED = 0;
+
+ static final int TESTS_FAILED = 1;
+
+ @Test
+ void test1()
+ {
+ }
+
+ @Test
+ void test2()
+ {
+ }
+
+ @Disabled
+ @Test
+ void test3()
+ {
+ }
+
+ @Test
+ void test4()
+ {
+ throw new RuntimeException();
+ }
+ }
+
+ static class TestClass2
+ {
+
+ static final int TESTS_FOUND = 3;
+
+ static final int TESTS_STARTED = 3;
+
+ static final int TESTS_SKIPPED = 0;
+
+ static final int TESTS_SUCCEEDED = 1;
+
+ static final int TESTS_ABORTED = 1;
+
+ static final int TESTS_FAILED = 1;
+
+ @Test
+ void test1()
+ {
+ }
+
+ @Test
+ void test2()
+ {
+ throw new RuntimeException();
+ }
+
+ @Test
+ void test3()
+ {
+ assumeTrue( false );
+ }
+ }
+
+ static class VerboseTestClass
+ {
+ @Test
+ void test()
+ {
+ System.out.println( "stdout" );
+ System.err.println( "stderr" );
+ }
+ }
+
+ @Test
+ void usesClassNamesForXmlReport()
+ throws TestSetFailedException, InvocationTargetException
+ {
+ String[] classNames = { Sub1Tests.class.getName(), Sub2Tests.class.getName() };
+ ProviderParameters providerParameters =
+ providerParametersMock( Sub1Tests.class, Sub2Tests.class );
+
+ JUnitPlatformProvider jUnitPlatformProvider = new JUnitPlatformProvider( providerParameters );
+ TestsToRun testsToRun = newTestsToRun( Sub1Tests.class, Sub2Tests.class );
+
+ invokeProvider( jUnitPlatformProvider, testsToRun );
+ RunListener reporter = providerParameters.getReporterFactory().createReporter();
+
+ ArgumentCaptor<ReportEntry> reportEntryArgumentCaptor =
+ ArgumentCaptor.forClass( ReportEntry.class );
+ verify( reporter, times( 2 ) ).testSucceeded( reportEntryArgumentCaptor.capture() );
+
+ List<ReportEntry> allValues = reportEntryArgumentCaptor.getAllValues();
+ assertThat( allValues ).extracting( ReportEntry::getSourceName ).containsExactly( classNames );
+ }
+
+ static class AbstractTestClass
+ {
+ @Test
+ void test()
+ {
+ }
+ }
+
+ static class Sub1Tests
+ extends AbstractTestClass
+ {
+ }
+
+ static class Sub2Tests
+ extends AbstractTestClass
+ {
+ }
+
+ static class TestClass3
+ {
+ @Test
+ void prefix1Suffix1()
+ {
+ throw new RuntimeException();
+ }
+
+ @Test
+ void prefix2Suffix1()
+ {
+ throw new RuntimeException();
+ }
+
+ @Test
+ void prefix1Suffix2()
+ {
+ throw new RuntimeException();
+ }
+
+ @Test
+ void prefix2Suffix2()
+ {
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTests.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTests.java
new file mode 100644
index 0000000..d3ec7a4
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTests.java
@@ -0,0 +1,580 @@
+package org.apache.maven.surefire.junitplatform;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singleton;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.platform.engine.TestExecutionResult.successful;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import org.apache.maven.surefire.report.ReportEntry;
+import org.apache.maven.surefire.report.RunListener;
+import org.apache.maven.surefire.report.SimpleReportEntry;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.engine.descriptor.ClassTestDescriptor;
+import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor;
+import org.junit.platform.engine.TestDescriptor;
+import org.junit.platform.engine.TestDescriptor.Type;
+import org.junit.platform.engine.TestExecutionResult;
+import org.junit.platform.engine.TestSource;
+import org.junit.platform.engine.UniqueId;
+import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor;
+import org.junit.platform.engine.support.descriptor.ClassSource;
+import org.junit.platform.engine.support.descriptor.EngineDescriptor;
+import org.junit.platform.launcher.TestIdentifier;
+import org.junit.platform.launcher.TestPlan;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+
+/**
+ * Unit tests for {@link RunListenerAdapter}.
+ *
+ * @since 1.0
+ */
+class RunListenerAdapterTests
+{
+
+ private RunListener listener;
+
+ private RunListenerAdapter adapter;
+
+ @BeforeEach
+ void setUp()
+ {
+ listener = mock( RunListener.class );
+ adapter = new RunListenerAdapter( listener );
+ adapter.testPlanExecutionStarted( TestPlan.from( emptyList() ) );
+ }
+
+ @Test
+ void notifiedWithCorrectNamesWhenMethodExecutionStarted()
+ throws Exception
+ {
+ ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+
+ TestPlan testPlan =
+ TestPlan.from( Collections.singletonList( new EngineDescriptor( newId(), "Luke's Plan" ) ) );
+ adapter.testPlanExecutionStarted( testPlan );
+
+ TestIdentifier methodIdentifier =
+ identifiersAsParentOnTestPlan( testPlan, newClassDescriptor(), newMethodDescriptor() );
+
+ adapter.executionStarted( methodIdentifier );
+ verify( listener ).testStarting( entryCaptor.capture() );
+
+ ReportEntry entry = entryCaptor.getValue();
+ assertEquals( MY_TEST_METHOD_NAME, entry.getName() );
+ assertEquals( MyTestClass.class.getName(), entry.getSourceName() );
+ assertNull( entry.getStackTraceWriter() );
+ }
+
+ @Test
+ void notifiedWithCompatibleNameForMethodWithArguments()
+ throws Exception
+ {
+ ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+
+ TestPlan testPlan =
+ TestPlan.from( Collections.singletonList( new EngineDescriptor( newId(), "Luke's Plan" ) ) );
+ adapter.testPlanExecutionStarted( testPlan );
+
+ TestIdentifier methodIdentifier =
+ identifiersAsParentOnTestPlan(
+ testPlan, newClassDescriptor(), newMethodDescriptor( String.class ) );
+
+ adapter.executionStarted( methodIdentifier );
+ verify( listener ).testStarting( entryCaptor.capture() );
+
+ ReportEntry entry = entryCaptor.getValue();
+ assertEquals( MY_TEST_METHOD_NAME + "{String}", entry.getName() );
+ assertEquals( MyTestClass.class.getName(), entry.getSourceName() );
+ assertNull( entry.getStackTraceWriter() );
+ }
+
+ @Test
+ void notifiedEagerlyForTestSetWhenClassExecutionStarted()
+ throws Exception
+ {
+ EngineDescriptor engine = newEngineDescriptor();
+ TestDescriptor parent = newClassDescriptor();
+ engine.addChild( parent );
+ TestDescriptor child = newMethodDescriptor();
+ parent.addChild( child );
+ TestPlan plan = TestPlan.from( Collections.singletonList( engine ) );
+
+ adapter.testPlanExecutionStarted( plan );
+ adapter.executionStarted( TestIdentifier.from( engine ) );
+ adapter.executionStarted( TestIdentifier.from( parent ) );
+ verify( listener )
+ .testSetStarting(
+ new SimpleReportEntry(
+ JUnitPlatformProvider.class.getName(),
+ MyTestClass.class.getName() ) );
+ verifyNoMoreInteractions( listener );
+
+ adapter.executionStarted( TestIdentifier.from( child ) );
+ verify( listener )
+ .testStarting( new SimpleReportEntry( MyTestClass.class.getName(), MY_TEST_METHOD_NAME ) );
+ verifyNoMoreInteractions( listener );
+
+ adapter.executionFinished( TestIdentifier.from( child ), successful() );
+ verify( listener )
+ .testSucceeded( new SimpleReportEntry( MyTestClass.class.getName(), MY_TEST_METHOD_NAME ) );
+ verifyNoMoreInteractions( listener );
+
+ adapter.executionFinished( TestIdentifier.from( parent ), successful() );
+ verify( listener )
+ .testSetCompleted(
+ new SimpleReportEntry(
+ JUnitPlatformProvider.class.getName(),
+ MyTestClass.class.getName() ) );
+ verifyNoMoreInteractions( listener );
+
+ adapter.executionFinished( TestIdentifier.from( engine ), successful() );
+ verifyNoMoreInteractions( listener );
+ }
+
+ @Test
+ void notifiedLazilyForTestSetWhenFirstTestWithoutClassDescriptorParentStarted()
+ {
+ EngineDescriptor engine = newEngineDescriptor();
+ TestDescriptor parent =
+ newTestDescriptor(
+ engine.getUniqueId().append( "container", "noClass" ), "parent",
+ Type.CONTAINER );
+ engine.addChild( parent );
+ TestDescriptor child1 =
+ newTestDescriptor( parent.getUniqueId().append( "test", "child1" ), "child1", Type.TEST );
+ parent.addChild( child1 );
+ TestDescriptor child2 =
+ newTestDescriptor( parent.getUniqueId().append( "test", "child2" ), "child2", Type.TEST );
+ parent.addChild( child2 );
+ TestPlan plan = TestPlan.from( Collections.singletonList( engine ) );
+
+ adapter.testPlanExecutionStarted( plan );
+ adapter.executionStarted( TestIdentifier.from( engine ) );
+ adapter.executionStarted( TestIdentifier.from( parent ) );
+ verifyZeroInteractions( listener );
+
+ adapter.executionStarted( TestIdentifier.from( child1 ) );
+ InOrder inOrder = inOrder( listener );
+ inOrder
+ .verify( listener )
+ .testSetStarting( new SimpleReportEntry( JUnitPlatformProvider.class.getName(), "parent" ) );
+ inOrder.verify( listener ).testStarting( new SimpleReportEntry( "parent", "child1" ) );
+ inOrder.verifyNoMoreInteractions();
+
+ adapter.executionFinished( TestIdentifier.from( child1 ), successful() );
+ verify( listener ).testSucceeded( new SimpleReportEntry( "parent", "child1" ) );
+ verifyNoMoreInteractions( listener );
+
+ adapter.executionStarted( TestIdentifier.from( child2 ) );
+ verify( listener ).testStarting( new SimpleReportEntry( "parent", "child2" ) );
+ verifyNoMoreInteractions( listener );
+
+ adapter.executionFinished( TestIdentifier.from( child2 ), successful() );
+ verify( listener ).testSucceeded( new SimpleReportEntry( "parent", "child2" ) );
+ verifyNoMoreInteractions( listener );
+
+ adapter.executionFinished( TestIdentifier.from( parent ), successful() );
+ verify( listener )
+ .testSetCompleted( new SimpleReportEntry( JUnitPlatformProvider.class.getName(), "parent" ) );
+ verifyNoMoreInteractions( listener );
+
+ adapter.executionFinished( TestIdentifier.from( engine ), successful() );
+ verifyNoMoreInteractions( listener );
+ }
+
+ @Test
+ void notifiedForTestSetForSingleNodeEngine()
+ {
+ EngineDescriptor engine =
+ new EngineDescriptor( UniqueId.forEngine( "engine" ), "engine" )
+ {
+ @Override
+ public Type getType()
+ {
+ return Type.TEST;
+ }
+ };
+ TestPlan plan = TestPlan.from( Collections.singletonList( engine ) );
+
+ adapter.testPlanExecutionStarted( plan );
+ adapter.executionStarted( TestIdentifier.from( engine ) );
+ InOrder inOrder = inOrder( listener );
+ inOrder
+ .verify( listener )
+ .testSetStarting( new SimpleReportEntry( JUnitPlatformProvider.class.getName(), "engine" ) );
+ inOrder.verify( listener ).testStarting( new SimpleReportEntry( "<unrooted>", "engine" ) );
+ inOrder.verifyNoMoreInteractions();
+
+ adapter.executionFinished( TestIdentifier.from( engine ), successful() );
+ inOrder = inOrder( listener );
+ inOrder.verify( listener ).testSucceeded( new SimpleReportEntry( "<unrooted>", "engine" ) );
+ inOrder
+ .verify( listener )
+ .testSetCompleted( new SimpleReportEntry( JUnitPlatformProvider.class.getName(), "engine" ) );
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ void notNotifiedWhenEngineExecutionStarted()
+ throws Exception
+ {
+ adapter.executionStarted( newEngineIdentifier() );
+ verify( listener, never() ).testStarting( any() );
+ }
+
+ @Test
+ void notifiedWhenMethodExecutionSkipped()
+ throws Exception
+ {
+ adapter.executionSkipped( newMethodIdentifier(), "test" );
+ verify( listener ).testSkipped( any() );
+ }
+
+ @Test
+ void notifiedWithCorrectNamesWhenClassExecutionSkipped()
+ throws Exception
+ {
+ ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+ TestPlan testPlan =
+ TestPlan.from( Collections.singletonList( new EngineDescriptor( newId(), "Luke's Plan" ) ) );
+ adapter.testPlanExecutionStarted( testPlan );
+
+ TestIdentifier classIdentifier =
+ identifiersAsParentOnTestPlan( testPlan, newEngineDescriptor(), newClassDescriptor() );
+
+ adapter.executionSkipped( classIdentifier, "test" );
+ verify( listener ).testSkipped( entryCaptor.capture() );
+
+ ReportEntry entry = entryCaptor.getValue();
+ assertTrue( MyTestClass.class.getTypeName().contains( entry.getName() ) );
+ assertEquals( MyTestClass.class.getTypeName(), entry.getSourceName() );
+ }
+
+ @Test
+ void notifiedWhenEngineExecutionSkipped()
+ throws Exception
+ {
+ adapter.executionSkipped( newEngineIdentifier(), "test" );
+ verify( listener ).testSkipped( any() );
+ }
+
+ @Test
+ void notifiedWhenMethodExecutionAborted()
+ throws Exception
+ {
+ adapter.executionFinished( newMethodIdentifier(), TestExecutionResult.aborted( null ) );
+ verify( listener ).testAssumptionFailure( any() );
+ }
+
+ @Test
+ void notifiedWhenClassExecutionAborted()
+ throws Exception
+ {
+ adapter.executionFinished( newClassIdentifier(), TestExecutionResult.aborted( null ) );
+ verify( listener ).testAssumptionFailure( any() );
+ }
+
+ @Test
+ void notifiedWhenMethodExecutionFailedWithAnAssertionError()
+ throws Exception
+ {
+ adapter.executionFinished(
+ newMethodIdentifier(), TestExecutionResult.failed( new AssertionError() ) );
+ verify( listener ).testFailed( any() );
+ }
+
+ @Test
+ void notifiedWhenMethodExecutionFailedWithANonAssertionError()
+ throws Exception
+ {
+ adapter.executionFinished(
+ newMethodIdentifier(), TestExecutionResult.failed( new RuntimeException() ) );
+ verify( listener ).testError( any() );
+ }
+
+ @Test
+ void notifiedWithCorrectNamesWhenClassExecutionFailed()
+ throws Exception
+ {
+ ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+ TestPlan testPlan =
+ TestPlan.from( Collections.singletonList( new EngineDescriptor( newId(), "Luke's Plan" ) ) );
+ adapter.testPlanExecutionStarted( testPlan );
+
+ adapter.executionFinished(
+ identifiersAsParentOnTestPlan( testPlan, newEngineDescriptor(), newClassDescriptor() ),
+ TestExecutionResult.failed( new AssertionError() ) );
+ verify( listener ).testFailed( entryCaptor.capture() );
+
+ ReportEntry entry = entryCaptor.getValue();
+ assertEquals( MyTestClass.class.getTypeName(), entry.getSourceName() );
+ assertNotNull( entry.getStackTraceWriter() );
+ }
+
+ @Test
+ void notifiedWhenMethodExecutionSucceeded()
+ throws Exception
+ {
+ adapter.executionFinished( newMethodIdentifier(), successful() );
+ verify( listener ).testSucceeded( any() );
+ }
+
+ @Test
+ void notifiedForTestSetWhenClassExecutionSucceeded()
+ throws Exception
+ {
+ EngineDescriptor engineDescriptor = newEngineDescriptor();
+ TestDescriptor classDescriptor = newClassDescriptor();
+ engineDescriptor.addChild( classDescriptor );
+ adapter.testPlanExecutionStarted( TestPlan.from( singleton( engineDescriptor ) ) );
+ adapter.executionStarted( TestIdentifier.from( classDescriptor ) );
+
+ adapter.executionFinished( TestIdentifier.from( classDescriptor ), successful() );
+
+ verify( listener )
+ .testSetCompleted(
+ new SimpleReportEntry(
+ JUnitPlatformProvider.class.getName(),
+ MyTestClass.class.getName() ) );
+ verify( listener, never() ).testSucceeded( any() );
+ }
+
+ @Test
+ void notifiedWithParentDisplayNameWhenTestClassUnknown()
+ throws Exception
+ {
+ // Set up a test plan
+ TestPlan plan =
+ TestPlan.from( Collections.singletonList( new EngineDescriptor( newId(), "Luke's Plan" ) ) );
+ adapter.testPlanExecutionStarted( plan );
+
+ // Use the test plan to set up child with parent.
+ final String parentDisplay = "I am your father";
+ TestIdentifier child = newSourcelessChildIdentifierWithParent( plan, parentDisplay, null );
+ adapter.executionStarted( child );
+
+ // Check that the adapter has informed Surefire that the test has been invoked,
+ // with the parent name as source (since the test case itself had no source).
+ ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+ verify( listener ).testStarting( entryCaptor.capture() );
+ assertEquals( parentDisplay, entryCaptor.getValue().getSourceName() );
+ }
+
+ @Test
+ void stackTraceWriterPresentWhenParentHasSource()
+ throws Exception
+ {
+ TestPlan plan =
+ TestPlan.from( Collections.singletonList( new EngineDescriptor( newId(), "Some Plan" ) ) );
+ adapter.testPlanExecutionStarted( plan );
+
+ TestIdentifier child =
+ newSourcelessChildIdentifierWithParent( plan, "Parent", ClassSource.from( MyTestClass.class ) );
+ adapter.executionFinished( child, TestExecutionResult.failed( new RuntimeException() ) );
+ ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+ verify( listener ).testError( entryCaptor.capture() );
+ assertNotNull( entryCaptor.getValue().getStackTraceWriter() );
+ }
+
+ @Test
+ void stackTraceWriterDefaultsToTestClass()
+ throws Exception
+ {
+ TestPlan plan =
+ TestPlan.from( Collections.singletonList( new EngineDescriptor( newId(), "Some Plan" ) ) );
+ adapter.testPlanExecutionStarted( plan );
+
+ TestIdentifier child = newSourcelessChildIdentifierWithParent( plan, "Parent", null );
+ adapter.executionFinished( child, TestExecutionResult.failed( new RuntimeException( "message" ) ) );
+ ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+ verify( listener ).testError( entryCaptor.capture() );
+ assertNotNull( entryCaptor.getValue().getStackTraceWriter() );
+ assertNotNull( entryCaptor.getValue().getStackTraceWriter().smartTrimmedStackTrace() );
+ assertNotNull( entryCaptor.getValue().getStackTraceWriter().writeTraceToString() );
+ assertNotNull( entryCaptor.getValue().getStackTraceWriter().writeTrimmedTraceToString() );
+ }
+
+ @Test
+ void stackTraceWriterPresentEvenWithoutException()
+ throws Exception
+ {
+ adapter.executionFinished( newMethodIdentifier(), TestExecutionResult.failed( null ) );
+ ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+ verify( listener ).testError( entryCaptor.capture() );
+ assertNotNull( entryCaptor.getValue().getStackTraceWriter() );
+ }
+
+ @Test
+ void displayNamesIgnoredInReport()
+ throws NoSuchMethodException
+ {
+ TestMethodTestDescriptor descriptor =
+ new TestMethodTestDescriptor(
+ newId(), MyTestClass.class,
+ MyTestClass.class.getDeclaredMethod( "myNamedTestMethod" ) );
+
+ TestIdentifier factoryIdentifier = TestIdentifier.from( descriptor );
+ ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass( ReportEntry.class );
+
+ adapter.executionSkipped( factoryIdentifier, "" );
+ verify( listener ).testSkipped( entryCaptor.capture() );
+
+ ReportEntry value = entryCaptor.getValue();
+
+ assertEquals( "myNamedTestMethod", value.getName() );
+ }
+
+ private static TestIdentifier newMethodIdentifier()
+ throws Exception
+ {
+ return TestIdentifier.from( newMethodDescriptor() );
+ }
+
+ private static TestDescriptor newMethodDescriptor( Class<?>... parameterTypes )
+ throws Exception
+ {
+ return new TestMethodTestDescriptor(
+ UniqueId.forEngine( "method" ),
+ MyTestClass.class,
+ MyTestClass.class.getDeclaredMethod( MY_TEST_METHOD_NAME, parameterTypes ) );
+ }
+
+ private static TestIdentifier newClassIdentifier()
+ {
+ return TestIdentifier.from( newClassDescriptor() );
+ }
+
+ private static TestDescriptor newClassDescriptor()
+ {
+ return new ClassTestDescriptor(
+ UniqueId.root( "class", MyTestClass.class.getName() ), MyTestClass.class );
+ }
+
+ private static TestIdentifier newSourcelessChildIdentifierWithParent(
+ TestPlan testPlan, String parentDisplay, TestSource parentTestSource )
+ {
+ // A parent test identifier with a name.
+ TestDescriptor parent = mock( TestDescriptor.class );
+ when( parent.getUniqueId() ).thenReturn( newId() );
+ when( parent.getDisplayName() ).thenReturn( parentDisplay );
+ when( parent.getLegacyReportingName() ).thenReturn( parentDisplay );
+ when( parent.getSource() ).thenReturn( Optional.ofNullable( parentTestSource ) );
+ when( parent.getType() ).thenReturn( Type.CONTAINER );
+ TestIdentifier parentId = TestIdentifier.from( parent );
+
+ // The (child) test case that is to be executed as part of a test plan.
+ TestDescriptor child = mock( TestDescriptor.class );
+ when( child.getUniqueId() ).thenReturn( newId() );
+ when( child.getType() ).thenReturn( Type.TEST );
+ when( child.getLegacyReportingName() ).thenReturn( "child" );
+
+ // Ensure the child source is null yet that there is a parent -- the special case to be tested.
+ when( child.getSource() ).thenReturn( Optional.empty() );
+ when( child.getParent() ).thenReturn( Optional.of( parent ) );
+ TestIdentifier childId = TestIdentifier.from( child );
+
+ testPlan.add( childId );
+ testPlan.add( parentId );
+
+ return childId;
+ }
+
+ private static TestIdentifier newEngineIdentifier()
+ {
+ TestDescriptor testDescriptor = newEngineDescriptor();
+ return TestIdentifier.from( testDescriptor );
+ }
+
+ private static EngineDescriptor newEngineDescriptor()
+ {
+ return new EngineDescriptor( UniqueId.forEngine( "engine" ), "engine" );
+ }
+
+ private TestDescriptor newTestDescriptor( UniqueId uniqueId, String displayName, Type type )
+ {
+ return new AbstractTestDescriptor( uniqueId, displayName )
+ {
+ @Override
+ public Type getType()
+ {
+ return type;
+ }
+ };
+ }
+
+ private static TestIdentifier identifiersAsParentOnTestPlan(
+ TestPlan plan, TestDescriptor parent, TestDescriptor child )
+ {
+ child.setParent( parent );
+
+ TestIdentifier parentIdentifier = TestIdentifier.from( parent );
+ TestIdentifier childIdentifier = TestIdentifier.from( child );
+
+ plan.add( parentIdentifier );
+ plan.add( childIdentifier );
+
+ return childIdentifier;
+ }
+
+ private static UniqueId newId()
+ {
+ return UniqueId.forEngine( "engine" );
+ }
+
+ private static final String MY_TEST_METHOD_NAME = "myTestMethod";
+
+ private static class MyTestClass
+ {
+ @Test
+ void myTestMethod()
+ {
+ }
+
+ @Test
+ void myTestMethod( String foo )
+ {
+ }
+
+ @DisplayName( "name" )
+ @Test
+ void myNamedTestMethod()
+ {
+ }
+ }
+}
diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestMethodFilterTests.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestMethodFilterTests.java
new file mode 100644
index 0000000..29ca326
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestMethodFilterTests.java
@@ -0,0 +1,105 @@
+package org.apache.maven.surefire.junitplatform;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.apache.maven.surefire.testset.TestListResolver.toClassFileName;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Method;
+
+import org.apache.maven.surefire.testset.TestListResolver;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.engine.descriptor.ClassTestDescriptor;
+import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor;
+import org.junit.platform.engine.FilterResult;
+import org.junit.platform.engine.UniqueId;
+
+/**
+ * Unit tests for {@link TestMethodFilter}.
+ *
+ * @since 1.0.3
+ */
+class TestMethodFilterTests
+{
+
+ private final TestListResolver resolver = mock( TestListResolver.class );
+
+ private final TestMethodFilter filter = new TestMethodFilter( this.resolver );
+
+ @Test
+ void includesBasedOnTestListResolver()
+ throws Exception
+ {
+ when( resolver.shouldRun( toClassFileName( TestClass.class ), "testMethod" ) ).thenReturn( true );
+
+ FilterResult result = filter.apply( newTestMethodDescriptor() );
+
+ assertTrue( result.included() );
+ assertFalse( result.excluded() );
+ }
+
+ @Test
+ void excludesBasedOnTestListResolver()
+ throws Exception
+ {
+ when( resolver.shouldRun( toClassFileName( TestClass.class ), "testMethod" ) ).thenReturn( false );
+
+ FilterResult result = filter.apply( newTestMethodDescriptor() );
+
+ assertFalse( result.included() );
+ assertTrue( result.excluded() );
+ }
+
+ @Test
+ void includesTestDescriptorWithClassSource()
+ throws Exception
+ {
+ FilterResult result = filter.apply( newClassTestDescriptor() );
+
+ assertTrue( result.included() );
+ assertFalse( result.excluded() );
+ }
+
+ private static TestMethodTestDescriptor newTestMethodDescriptor()
+ throws Exception
+ {
+ UniqueId uniqueId = UniqueId.forEngine( "method" );
+ Class<TestClass> testClass = TestClass.class;
+ Method testMethod = testClass.getMethod( "testMethod" );
+ return new TestMethodTestDescriptor( uniqueId, testClass, testMethod );
+ }
+
+ private static ClassTestDescriptor newClassTestDescriptor()
+ throws Exception
+ {
+ UniqueId uniqueId = UniqueId.forEngine( "class" );
+ return new ClassTestDescriptor( uniqueId, TestClass.class );
+ }
+
+ public static class TestClass
+ {
+ public void testMethod()
+ {
+ }
+ }
+}
diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestPlanScannerFilterTests.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestPlanScannerFilterTests.java
new file mode 100644
index 0000000..8ecedc7
--- /dev/null
+++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/TestPlanScannerFilterTests.java
@@ -0,0 +1,188 @@
+package org.apache.maven.surefire.junitplatform;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import static java.util.Collections.emptyList;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestFactory;
+import org.junit.platform.engine.Filter;
+import org.junit.platform.launcher.core.LauncherFactory;
+
+/**
+ * Unit tests for {@link TestPlanScannerFilter}.
+ *
+ * @since 1.0
+ */
+class TestPlanScannerFilterTests
+{
+
+ @Test
+ void emptyClassIsNotAccepted()
+ {
+ assertFalse( newFilter().accept( EmptyClass.class ), "does not accept empty class" );
+ }
+
+ @Test
+ void classWithNoTestMethodsIsNotAccepted()
+ {
+ assertFalse(
+ newFilter().accept( ClassWithMethods.class ), "does not accept class with no @Test methods" );
+ }
+
+ @Test
+ void classWithTestMethodsIsAccepted()
+ {
+ assertTrue( newFilter().accept( ClassWithTestMethods.class ) );
+ }
+
+ @Test
+ void classWithNestedTestClassIsAccepted()
+ {
+ assertTrue( newFilter().accept( ClassWithNestedTestClass.class ) );
+ }
+
+ @Test
+ void classWithDeeplyNestedTestClassIsAccepted()
+ {
+ assertTrue( newFilter().accept( ClassWithDeeplyNestedTestClass.class ) );
+ }
+
+ @Test
+ void classWithTestFactoryIsAccepted()
+ {
+ assertTrue( newFilter().accept( ClassWithTestFactory.class ) );
+ }
+
+ @Test
+ void classWithNestedTestFactoryIsAccepted()
+ {
+ assertTrue( newFilter().accept( ClassWithNestedTestFactory.class ) );
+ }
+
+ private TestPlanScannerFilter newFilter()
+ {
+ return new TestPlanScannerFilter( LauncherFactory.create(), new Filter<?>[0] );
+ }
+
+ static class EmptyClass
+ {
+ }
+
+ static class ClassWithMethods
+ {
+
+ void method1()
+ {
+ }
+
+ void method2()
+ {
+ }
+ }
+
+ static class ClassWithTestMethods
+ {
+
+ @Test
+ void test1()
+ {
+ }
+
+ @Test
+ public void test2()
+ {
+ }
+ }
+
+ static class ClassWithNestedTestClass
+ {
+
+ void method()
+ {
+ }
+
+ @Nested
+ class TestClass
+ {
+
+ @Test
+ void test1()
+ {
+ }
+ }
+ }
+
+ static class ClassWithDeeplyNestedTestClass
+ {
+
+ @Nested
+ class Level1
+ {
+
+ @Nested
+ class Level2
+ {
+
+ @Nested
+ class TestClass
+ {
+
+ @Test
+ void test1()
+ {
+ }
+ }
+ }
+ }
+ }
+
+ static class ClassWithTestFactory
+ {
+
+ @TestFactory
+ Stream<DynamicTest> tests()
+ {
+ return Stream.empty();
+ }
+ }
+
+ static class ClassWithNestedTestFactory
+ {
+
+ @Nested
+ class TestClass
+ {
+
+ @TestFactory
+ List<DynamicTest> tests()
+ {
+ return emptyList();
+ }
+ }
+ }
+}
--
To stop receiving notification emails like this one, please contact
tibordigana@apache.org.