This is an automated email from the ASF dual-hosted git repository. sor pushed a commit to branch 1330 in repository https://gitbox.apache.org/repos/asf/maven-surefire.git
commit 6a879040f66e2bc389106a0aabf0d65c878bc330 Author: Tibor17 <tibordig...@apache.org> AuthorDate: Fri Apr 13 23:51:33 2018 +0200 [SUREFIRE-1330] JUnit 5 surefire-provider code donation --- .../plugin/surefire/AbstractSurefireMojo.java | 71 +- pom.xml | 9 +- surefire-its/pom.xml | 19 - .../maven/surefire/its/JUnit4VersionsIT.java | 70 +- .../apache/maven/surefire/its/JUnitPlatformIT.java | 76 +++ .../apache/maven/surefire/its/JUnitVersion.java} | 67 +- .../test/resources/junit-platform-1.0.0/pom.xml | 60 ++ .../JUnitPlatform_1_0_0_Test.java} | 42 +- .../test/resources/junit-platform-1.1.1/pom.xml | 60 ++ .../JUnitPlatform_1_1_1_Test.java} | 42 +- .../test/resources/junit-platform-1.2.0/pom.xml | 60 ++ .../JUnitPlatform_1_2_0_Test.java} | 42 +- .../pom.xml | 60 +- .../junitplatformenginejqwik/BasicJQwikTest.java} | 44 +- .../junit-platform-engine-jupiter/pom.xml | 67 ++ .../BasicJupiterTest.java | 82 +++ .../junit-platform-engine-vintage/pom.xml | 60 ++ .../BasicVintageTest.java} | 12 +- surefire-its/src/test/resources/junit4/pom.xml | 56 +- .../junit4/src/test/java/junit4/BasicTest.java | 4 +- surefire-providers/pom.xml | 1 + surefire-providers/surefire-junit-platform/pom.xml | 164 +++++ .../junitplatform/JUnitPlatformProvider.java | 246 +++++++ .../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 +++++ 31 files changed, 3140 insertions(+), 296 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 d99cbac..5fffd47 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 @@ -488,6 +488,15 @@ public abstract class AbstractSurefireMojo private String junitArtifactName; /** + * Allows you to specify the name of the JUnit Platform artifact. + * If not set, {@code org.junit.platform:junit-platform-engine} will be used. + * + * @since 2.22.0 + */ + @Parameter( property = "junitPlatformArtifactName", defaultValue = "org.junit.platform:junit-platform-engine" ) + private String junitPlatformArtifactName; + + /** * Allows you to specify the name of the TestNG artifact. If not set, {@code org.testng:testng} will be used. * * @since 2.3.1 @@ -1057,6 +1066,7 @@ public abstract class AbstractSurefireMojo Artifact junitDepArtifact = getJunitDepArtifact(); return new ProviderList( new DynamicProviderInfo( null ), new TestNgProviderInfo( getTestNgArtifact() ), + new JUnitPlatformProviderInfo( getJunitPlatformArtifact() ), new JUnitCoreProviderInfo( getJunitArtifact(), junitDepArtifact ), new JUnit4ProviderInfo( getJunitArtifact(), junitDepArtifact ), new JUnit3ProviderInfo() ) @@ -1575,7 +1585,7 @@ public abstract class AbstractSurefireMojo return dependencyResolver.isWithinVersionSpec( artifact, "[4.0,)" ); } - static boolean isForkModeNever( String forkMode ) + private static boolean isForkModeNever( String forkMode ) { return FORK_NEVER.equals( forkMode ); } @@ -2068,6 +2078,21 @@ public abstract class AbstractSurefireMojo return getProjectArtifactMap().get( "junit:junit-dep" ); } + + private Artifact getJunitPlatformArtifact() + { + Artifact artifact = getProjectArtifactMap().get( getJunitPlatformArtifactName() ); + Artifact projectArtifact = project.getArtifact(); + String projectArtifactName = projectArtifact.getGroupId() + ":" + projectArtifact.getArtifactId(); + + if ( artifact == null && projectArtifactName.equals( getJunitPlatformArtifactName() ) ) + { + artifact = projectArtifact; + } + + return artifact; + } + private ForkStarter createForkStarter( @Nonnull ProviderInfo provider, @Nonnull ForkConfiguration forkConfiguration, @Nonnull ClassLoaderConfiguration classLoaderConfiguration, @Nonnull RunOrderParameters runOrderParameters, @Nonnull ConsoleLogger log, @@ -2908,6 +2933,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 junitArtifact != null; + } + + 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 { @@ -3364,6 +3422,17 @@ public abstract class AbstractSurefireMojo this.junitArtifactName = junitArtifactName; } + public String getJunitPlatformArtifactName() + { + return junitPlatformArtifactName; + } + + @SuppressWarnings( "UnusedDeclaration" ) + public void setJunitPlatformArtifactName( String junitPlatformArtifactName ) + { + this.junitPlatformArtifactName = junitPlatformArtifactName; + } + public String getTestNGArtifactName() { return testNGArtifactName; diff --git a/pom.xml b/pom.xml index 32b8e9d..34cf555 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> @@ -466,7 +468,7 @@ <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> - <version>0.7.9</version> + <version>0.8.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> @@ -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..8f4008f 100644 --- a/surefire-its/pom.xml +++ b/surefire-its/pom.xml @@ -143,25 +143,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..24d4d63 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,26 @@ 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; + /** * Basic suite test using all known versions of JUnit 4.x * @@ -44,44 +61,39 @@ 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 } } ); } @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/java/org/apache/maven/surefire/its/JUnitPlatformIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitPlatformIT.java new file mode 100644 index 0000000..db40002 --- /dev/null +++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/JUnitPlatformIT.java @@ -0,0 +1,76 @@ +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.SurefireJUnit4IntegrationTestCase; +import org.junit.Before; +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 JUnitPlatformIT + extends SurefireJUnit4IntegrationTestCase +{ + @Before + public void setUp() + { + assumeThat( "java.specification.version: ", + getProperty( "java.specification.version" ), is( greaterThanOrEqualTo( "1.8" ) ) ); + } + + @Test + public void testJupiterEngine() + { + unpack( "/junit-platform-engine-jupiter" ).executeTest().verifyErrorFree( 5 ); + } + + @Test + public void testVintageEngine() + { + unpack( "/junit-platform-engine-vintage" ).executeTest().verifyErrorFree( 1 ); + } + + @Test + public void testJQwikEngine() + { + unpack( "/junit-platform-engine-jqwik" ).executeTest().verifyErrorFree( 1 ); + } + + @Test + public void testJUnitPlatform_1_0_0() + { + unpack( "/junit-platform-1.0.0" ).executeTest().verifyErrorFree( 1 ); + } + + @Test + public void testJUnitPlatform_1_1_1() + { + unpack( "/junit-platform-1.1.1" ).executeTest().verifyErrorFree( 1 ); + } + + @Test + public void testJUnitPlatform_1_2_0() + { + unpack( "/junit-platform-1.2.0" ).executeTest().verifyErrorFree( 1 ); + } +} 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/JUnitVersion.java similarity index 50% 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/JUnitVersion.java index e9234f2..9549016 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/JUnitVersion.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,44 @@ 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.apache.maven.surefire.its.fixture.SurefireLauncher; - -public class BasicTest -{ - - 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() +/** + * 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" ); + + private final String version; + + JUnitVersion( String version ) { - setUpCalled = false; - tearDownCalled = true; - System.out.println( "Called tearDown" ); + this.version = version; } - @Test - public void testSetUp() + public SurefireLauncher configure( SurefireLauncher launcher ) { - Assert.assertTrue( "setUp was not called", setUpCalled ); + return launcher.setJUnitVersion( version ); } - - @AfterClass - public static void oneTimeTearDown() + public String toString() { - + return version; } - } diff --git a/surefire-its/src/test/resources/junit-platform-1.0.0/pom.xml b/surefire-its/src/test/resources/junit-platform-1.0.0/pom.xml new file mode 100644 index 0000000..1b6fd59 --- /dev/null +++ b/surefire-its/src/test/resources/junit-platform-1.0.0/pom.xml @@ -0,0 +1,60 @@ +<?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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.maven.plugins.surefire</groupId> + <artifactId>junit-platform-1.0.0</artifactId> + <version>1.0</version> + <name>Test for JUnit 5: Platform 1.0.0 + Jupiter 5.0.0</name> + + <properties> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + </properties> + + <!-- + Declare "junit-jupiter-engine" dependency because the + Jupiter Engine is needed at test runtime. Artifacts + needed for test compilation, like "junit-jupiter-api", + are pulled-in via transitive dependency resolution. + --> + <dependencies> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <version>5.0.0</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-1.0.0/src/test/java/junitplatform_1_0_0/JUnitPlatform_1_0_0_Test.java similarity index 52% copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java copy to surefire-its/src/test/resources/junit-platform-1.0.0/src/test/java/junitplatform_1_0_0/JUnitPlatform_1_0_0_Test.java index e9234f2..760d874 100644 --- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java +++ b/surefire-its/src/test/resources/junit-platform-1.0.0/src/test/java/junitplatform_1_0_0/JUnitPlatform_1_0_0_Test.java @@ -1,4 +1,4 @@ -package junit4; +package junitplatform_1_0_0; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -19,47 +19,19 @@ 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.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; -public class BasicTest +class JUnitPlatform_1_0_0_Test { - 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() + void test(TestInfo info) { - Assert.assertTrue( "setUp was not called", setUpCalled ); + assertEquals( "test(TestInfo)", info.getDisplayName(), "display name mismatch" ); } - - @AfterClass - public static void oneTimeTearDown() - { - - } } diff --git a/surefire-its/src/test/resources/junit-platform-1.1.1/pom.xml b/surefire-its/src/test/resources/junit-platform-1.1.1/pom.xml new file mode 100644 index 0000000..2555d8b --- /dev/null +++ b/surefire-its/src/test/resources/junit-platform-1.1.1/pom.xml @@ -0,0 +1,60 @@ +<?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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.maven.plugins.surefire</groupId> + <artifactId>junit-platform-1.1.1</artifactId> + <version>1.0</version> + <name>Test for JUnit 5: Platform 1.1.1 + Jupiter 5.1.1</name> + + <properties> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + </properties> + + <!-- + Declare "junit-jupiter-engine" dependency because the + Jupiter Engine is needed at test runtime. Artifacts + needed for test compilation, like "junit-jupiter-api", + are pulled-in via transitive dependency resolution. + --> + <dependencies> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</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-1.1.1/src/test/java/junitplatform_1_1_1/JUnitPlatform_1_1_1_Test.java similarity index 52% copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java copy to surefire-its/src/test/resources/junit-platform-1.1.1/src/test/java/junitplatform_1_1_1/JUnitPlatform_1_1_1_Test.java index e9234f2..e1bc05e 100644 --- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java +++ b/surefire-its/src/test/resources/junit-platform-1.1.1/src/test/java/junitplatform_1_1_1/JUnitPlatform_1_1_1_Test.java @@ -1,4 +1,4 @@ -package junit4; +package junitplatform_1_1_1; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -19,47 +19,19 @@ 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.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; -public class BasicTest +class JUnitPlatform_1_1_1_Test { - 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() + void test(TestInfo info) { - Assert.assertTrue( "setUp was not called", setUpCalled ); + assertEquals( "test(TestInfo)", info.getDisplayName(), "display name mismatch" ); } - - @AfterClass - public static void oneTimeTearDown() - { - - } } diff --git a/surefire-its/src/test/resources/junit-platform-1.2.0/pom.xml b/surefire-its/src/test/resources/junit-platform-1.2.0/pom.xml new file mode 100644 index 0000000..8bc5638 --- /dev/null +++ b/surefire-its/src/test/resources/junit-platform-1.2.0/pom.xml @@ -0,0 +1,60 @@ +<?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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.maven.plugins.surefire</groupId> + <artifactId>junit-platform-1.2.0</artifactId> + <version>1.0</version> + <name>Test for JUnit 5: Platform 1.2.0 + Jupiter 5.2.0</name> + + <properties> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + </properties> + + <!-- + Declare "junit-jupiter-engine" dependency because the + Jupiter Engine is needed at test runtime. Artifacts + needed for test compilation, like "junit-jupiter-api", + are pulled-in via transitive dependency resolution. + --> + <dependencies> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <version>5.2.0</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-1.2.0/src/test/java/junitplatform_1_2_0/JUnitPlatform_1_2_0_Test.java similarity index 52% copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java copy to surefire-its/src/test/resources/junit-platform-1.2.0/src/test/java/junitplatform_1_2_0/JUnitPlatform_1_2_0_Test.java index e9234f2..c6ccbfc 100644 --- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java +++ b/surefire-its/src/test/resources/junit-platform-1.2.0/src/test/java/junitplatform_1_2_0/JUnitPlatform_1_2_0_Test.java @@ -1,4 +1,4 @@ -package junit4; +package junitplatform_1_2_0; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -19,47 +19,19 @@ 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.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; -public class BasicTest +class JUnitPlatform_1_2_0_Test { - 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() + void test(TestInfo info) { - Assert.assertTrue( "setUp was not called", setUpCalled ); + assertEquals( "test(TestInfo)", info.getDisplayName(), "display name mismatch" ); } - - @AfterClass - public static void oneTimeTearDown() - { - - } } diff --git a/surefire-its/src/test/resources/junit4/pom.xml b/surefire-its/src/test/resources/junit-platform-engine-jqwik/pom.xml similarity index 50% copy from surefire-its/src/test/resources/junit4/pom.xml copy to surefire-its/src/test/resources/junit-platform-engine-jqwik/pom.xml index 751a0e6..8e27d56 100644 --- a/surefire-its/src/test/resources/junit4/pom.xml +++ b/surefire-its/src/test/resources/junit-platform-engine-jqwik/pom.xml @@ -17,39 +17,43 @@ ~ 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-engine-jqwik</artifactId> + <version>1.0</version> + <name>Test for JUnit 5: Platform + JQwik</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> + <!-- + Declare "net.jqwik:jqwik" as test dependency. + Artifacts needed for test runtime, like "JUnit Platform", + are pulled-in via transitive dependency resolution. + --> + <dependencies> + <dependency> + <groupId>net.jqwik</groupId> + <artifactId>jqwik</artifactId> + <version>0.8.10</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-engine-jqwik/src/test/java/junitplatformenginejqwik/BasicJQwikTest.java similarity index 52% copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java copy to surefire-its/src/test/resources/junit-platform-engine-jqwik/src/test/java/junitplatformenginejqwik/BasicJQwikTest.java index e9234f2..27120ee 100644 --- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java +++ b/surefire-its/src/test/resources/junit-platform-engine-jqwik/src/test/java/junitplatformenginejqwik/BasicJQwikTest.java @@ -1,4 +1,4 @@ -package junit4; +package junitplatformenginejqwik; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -19,47 +19,15 @@ 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 net.jqwik.api.Example; - -public class BasicTest +class BasicJQwikTest { - 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() - { - Assert.assertTrue( "setUp was not called", setUpCalled ); - } - - - @AfterClass - public static void oneTimeTearDown() + @Example + boolean exampleFor1Plus3Equals4() { - + return ( 1 + 3 ) == 4; } } diff --git a/surefire-its/src/test/resources/junit-platform-engine-jupiter/pom.xml b/surefire-its/src/test/resources/junit-platform-engine-jupiter/pom.xml new file mode 100644 index 0000000..192cc8a --- /dev/null +++ b/surefire-its/src/test/resources/junit-platform-engine-jupiter/pom.xml @@ -0,0 +1,67 @@ +<?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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.maven.plugins.surefire</groupId> + <artifactId>junit-platform-engine-jupiter</artifactId> + <version>1.0</version> + <name>Test for JUnit 5: Platform + Jupiter</name> + + <properties> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + <junit.jupiter.version>5.2.0</junit.jupiter.version> + </properties> + + <!-- + Declare "junit-jupiter-engine" dependency because the + Jupiter Engine is needed at test runtime. Artifacts + needed for test compilation, like "junit-jupiter-api", + are pulled-in via transitive dependency resolution. + --> + <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.jupiter</groupId> + <artifactId>junit-jupiter-params</artifactId> + <version>${junit.jupiter.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> +</project> diff --git a/surefire-its/src/test/resources/junit-platform-engine-jupiter/src/test/java/junitplatformenginejupiter/BasicJupiterTest.java b/surefire-its/src/test/resources/junit-platform-engine-jupiter/src/test/java/junitplatformenginejupiter/BasicJupiterTest.java new file mode 100644 index 0000000..d85db86 --- /dev/null +++ b/surefire-its/src/test/resources/junit-platform-engine-jupiter/src/test/java/junitplatformenginejupiter/BasicJupiterTest.java @@ -0,0 +1,82 @@ +package junitplatformenginejupiter; + +/* + * 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.jupiter.api.Assertions.assertEquals; +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; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class BasicJupiterTest +{ + + private boolean setUpCalled; + + private static boolean tearDownCalled; + + @BeforeEach + void setUp() + { + setUpCalled = true; + tearDownCalled = false; + System.out.println( "Called setUp" ); + } + + @AfterEach + void tearDown() + { + setUpCalled = false; + tearDownCalled = true; + System.out.println( "Called tearDown" ); + } + + @Test + void test(TestInfo info) + { + assertTrue( setUpCalled, "setUp was not called" ); + assertEquals( "test(TestInfo)", info.getDisplayName(), "display name mismatch" ); + } + + @ParameterizedTest(name = "{0} + {1} = {2}") + @CsvSource({ + "0, 1, 1", + "1, 2, 3", + "49, 51, 100", + "1, 100, 101" + }) + void add(int first, int second, int expectedResult) + { + assertEquals(expectedResult, first + second, () -> first + " + " + second + " should equal " + expectedResult); + } + + + @AfterAll + static void oneTimeTearDown() + { + assertTrue( tearDownCalled ); + } + +} diff --git a/surefire-its/src/test/resources/junit-platform-engine-vintage/pom.xml b/surefire-its/src/test/resources/junit-platform-engine-vintage/pom.xml new file mode 100644 index 0000000..38b788f --- /dev/null +++ b/surefire-its/src/test/resources/junit-platform-engine-vintage/pom.xml @@ -0,0 +1,60 @@ +<?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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.maven.plugins.surefire</groupId> + <artifactId>junit-platform-engine-vintage</artifactId> + <version>1.0</version> + <name>Test for JUnit 5: Platform + Vintage</name> + + <properties> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + </properties> + + <!-- + Declare "junit-vintage-engine" dependency because the + Vintage Engine is needed at test runtime. Artifacts + needed for test compilation, like "junit:junit", + are pulled-in via transitive dependency resolution. + --> + <dependencies> + <dependency> + <groupId>org.junit.vintage</groupId> + <artifactId>junit-vintage-engine</artifactId> + <version>5.2.0</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-engine-vintage/src/test/java/junitplatformenginevintage/BasicVintageTest.java similarity index 91% copy from surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java copy to surefire-its/src/test/resources/junit-platform-engine-vintage/src/test/java/junitplatformenginevintage/BasicVintageTest.java index e9234f2..04e9aaf 100644 --- a/surefire-its/src/test/resources/junit4/src/test/java/junit4/BasicTest.java +++ b/surefire-its/src/test/resources/junit-platform-engine-vintage/src/test/java/junitplatformenginevintage/BasicVintageTest.java @@ -1,4 +1,4 @@ -package junit4; +package junitplatformenginevintage; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -25,14 +25,12 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; - -public class BasicTest +public class BasicVintageTest { + private static boolean tearDownCalled = false; private boolean setUpCalled = false; - private static boolean tearDownCalled = false; - @Before public void setUp() { @@ -54,12 +52,12 @@ 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/pom.xml b/surefire-its/src/test/resources/junit4/pom.xml index 751a0e6..d38e6fc 100644 --- a/surefire-its/src/test/resources/junit4/pom.xml +++ b/surefire-its/src/test/resources/junit4/pom.xml @@ -20,36 +20,36 @@ <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> + <properties> + <junitVersion>4.12</junitVersion> + <maven.compiler.source>1.7</maven.compiler.source> + <maven.compiler.target>1.7</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>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> </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-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..d8c6d63 --- /dev/null +++ b/surefire-providers/surefire-junit-platform/pom.xml @@ -0,0 +1,164 @@ +<!-- + ~ 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> + <ignores> + <param>org.junit.platform.commons.*</param> + </ignores> + </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..ded085e --- /dev/null +++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/JUnitPlatformProvider.java @@ -0,0 +1,246 @@ +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; + +/** + * JUnitPlatformProvider. + * + * @since 2.22.0 + */ +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; + + public 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..85227f3 --- /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 2.22.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..932c5ed --- /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 2.22.0 + */ +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..c054c85 --- /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 2.22.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..ea1df19 --- /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 2.22.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..97f6ffc --- /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 2.22.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..3e8b533 --- /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 2.22.0 + */ +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..a4f0883 --- /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 2.22.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 s...@apache.org.