This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 71055ec948 GROOVY-11788: Bump JUnit to 6.0.3
71055ec948 is described below
commit 71055ec948620ac2965477b586123c03682f8372
Author: Paul King <[email protected]>
AuthorDate: Sat Mar 28 22:34:58 2026 +1000
GROOVY-11788: Bump JUnit to 6.0.3
---
.../groovy/org.apache.groovy-documented.gradle | 2 +-
.../groovy/org.apache.groovy-performance.gradle | 6 +-
.../main/groovy/org.apache.groovy-tested.gradle | 6 +-
build.gradle | 2 +-
gradle/verification-metadata.xml | 42 +++++++
settings.gradle | 1 +
subprojects/groovy-test-junit5/build.gradle | 5 +-
.../build.gradle | 13 +-
.../junit6/plugin/GroovyJUnitRunnerHelper.groovy | 49 ++++++++
.../java/groovy/junit6/plugin/JUnit6Runner.java | 136 +++++++++++++++++++++
.../java/groovy/junit6/plugin/package-info.java | 23 ++++
.../services/org.apache.groovy.plugin.GroovyRunner | 20 +++
.../src/test/groovy/JUnit6Test.groovy | 60 +++++++++
versions.properties | 1 +
14 files changed, 349 insertions(+), 17 deletions(-)
diff --git a/build-logic/src/main/groovy/org.apache.groovy-documented.gradle
b/build-logic/src/main/groovy/org.apache.groovy-documented.gradle
index 9b191e0b54..789002e7e6 100644
--- a/build-logic/src/main/groovy/org.apache.groovy-documented.gradle
+++ b/build-logic/src/main/groovy/org.apache.groovy-documented.gradle
@@ -84,7 +84,7 @@ tasks.withType(Groovydoc).configureEach {
link "https://docs.oracle.com/javase/${17}/docs/api/java.base/", 'java.',
'org.xml.', 'javax.', 'org.w3c.'
link 'https://docs.groovy-lang.org/docs/ant/api/', 'org.apache.ant.',
'org.apache.tools.ant.'
link "https://junit.org/junit4/javadoc/${versions.junit}/", 'org.junit.',
'junit.'
- link
"https://docs.junit.org/${versions.junit5}/api/org.junit.jupiter.api/",
'org.junit.jupiter.', 'org.junit.platform.'
+ link "https://docs.junit.org/${versions.junit6}/api/",
'org.junit.jupiter.', 'org.junit.platform.'
link 'https://www.antlr.org/api/Java/', 'org.antlr.v4.'
link
'https://commons.apache.org/proper/commons-cli/javadocs/api-release/',
'org.apache.commons.cli.'
link 'https://picocli.info/apidocs/', 'picocli.'
diff --git a/build-logic/src/main/groovy/org.apache.groovy-performance.gradle
b/build-logic/src/main/groovy/org.apache.groovy-performance.gradle
index a4405f825f..f8555a2a9d 100644
--- a/build-logic/src/main/groovy/org.apache.groovy-performance.gradle
+++ b/build-logic/src/main/groovy/org.apache.groovy-performance.gradle
@@ -44,9 +44,9 @@ repositories {
dependencies {
jmh project(':')
testImplementation project(':')
- testImplementation "org.junit.jupiter:junit-jupiter-api:${versions.junit5}"
- testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${versions.junit5}"
- testRuntimeOnly
"org.junit.platform:junit-platform-launcher:${versions.junit5Platform}"
+ testImplementation "org.junit.jupiter:junit-jupiter-api:${versions.junit6}"
+ testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${versions.junit6}"
+ testRuntimeOnly
"org.junit.platform:junit-platform-launcher:${versions.junit6}"
stats "org.apache.commons:commons-math3:${versions.commonsMath3}"
}
diff --git a/build-logic/src/main/groovy/org.apache.groovy-tested.gradle
b/build-logic/src/main/groovy/org.apache.groovy-tested.gradle
index 4f588f9ea1..4d5c30ba89 100644
--- a/build-logic/src/main/groovy/org.apache.groovy-tested.gradle
+++ b/build-logic/src/main/groovy/org.apache.groovy-tested.gradle
@@ -35,9 +35,9 @@ sourceSets {
dependencies {
testCompileOnly "junit:junit:${versions.junit}"
- testImplementation "org.junit.jupiter:junit-jupiter:${versions.junit5}"
- testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${versions.junit5}"
- testRuntimeOnly
"org.junit.platform:junit-platform-launcher:${versions.junit5Platform}", {
+ testImplementation "org.junit.jupiter:junit-jupiter:${versions.junit6}"
+ testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${versions.junit6}"
+ testRuntimeOnly
"org.junit.platform:junit-platform-launcher:${versions.junit6}", {
exclude group: 'org.apiguardian', module: 'apiguardian-api'
}
}
diff --git a/build.gradle b/build.gradle
index ef6c4db67a..0143bc0880 100644
--- a/build.gradle
+++ b/build.gradle
@@ -122,7 +122,7 @@ dependencies {
testFixturesImplementation projects.groovyXml
testFixturesImplementation projects.groovyTest
- testFixturesImplementation
"org.junit.jupiter:junit-jupiter-api:${versions.junit5}"
+ testFixturesImplementation
"org.junit.jupiter:junit-jupiter-api:${versions.junit6}"
testFixturesImplementation "xmlunit:xmlunit:${versions.xmlunit}"
tools "com.eed3si9n.jarjar:ant-jarjar:${versions.jarjar}"
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 35e6d909ba..48077fa700 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -220,6 +220,7 @@
<trusting group="org.apache.commons"/>
</trusted-key>
<trusted-key id="BDB5FA4FE719D787FB3D3197F6D4A1D411E9D1AE"
group="com.google.guava"/>
+ <trusted-key id="BED597EFC4BF399D3283F697432DC97E7B73F0B6"
group="org.apache.ant"/>
<trusted-key id="C4F54D8622C95CC3F098721A0F13D5631D6AF36D"
group="org.testng" name="testng" version="7.10.2"/>
<trusted-key id="C668130C58722C9DC1C0FC633F1EB974E7AB9B37"
group="biz.aQute.bnd"/>
<trusted-key id="C7BE5BCC9FEC15518CFDA882B0F3710FA64900E7"
group="com.google.code.gson" name="gson"/>
@@ -2267,36 +2268,71 @@
<sha512
value="ec8c3f06c181ce7bc2803d7769701645b40f05d9d4ac948f9de6ed2ebaf76bba727d2b91d4d81defce082ac30215e29ede59028e5fd8d86bd5df1bbc5b7cea23"
origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="org.junit.jupiter" name="junit-jupiter"
version="6.0.3">
+ <artifact name="junit-jupiter-6.0.3.jar">
+ <sha512
value="a7e4e6ac16bb0efec4fe36941e61835c8e28c2de535bba6f1e69b84781eb3186fa7cb9b63ee4499f9dc42d332c271d50c8c27e9b1db77aca43ad00f2de4a5dc1"
origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.junit.jupiter" name="junit-jupiter-api"
version="5.14.3">
<artifact name="junit-jupiter-api-5.14.3.jar">
<sha512
value="5ada794d305920ceecc00ccd02c48f54bf3d4b36002810f543a2215eff5034519ba939c2451f42828ea4d0a19712cf1e9ec23dd0e91a6fe568bbd7ee023253d8"
origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="org.junit.jupiter" name="junit-jupiter-api"
version="6.0.3">
+ <artifact name="junit-jupiter-api-6.0.3.jar">
+ <sha512
value="145605177009d17d0d5698f7d827db805b5ea53fc54e67058cb1d8fdd79123a85da6f5e1a28fd8105d08175b74c5dd3a99928aa207ab00d734a1febfc70db1fb"
origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.junit.jupiter" name="junit-jupiter-engine"
version="5.14.3">
<artifact name="junit-jupiter-engine-5.14.3.jar">
<sha512
value="73de20444b8898e8fdbea282055807ac280676606e0bfabd25375e580cb5bcce163e9c3fa15828cd7600d364cd0bbac92554560cebed9e7e5116a3693b3fc074"
origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="org.junit.jupiter" name="junit-jupiter-engine"
version="6.0.3">
+ <artifact name="junit-jupiter-engine-6.0.3.jar">
+ <sha512
value="8d9b04a779d23c1fe76daf446de804dccca785d5f5f55df5d3b3aa373694a2c210e142b0e27d0ae56de28316bfd6c8cd4ac6bb93094b3cf959a867c4e333d226"
origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.junit.jupiter" name="junit-jupiter-params"
version="5.14.3">
<artifact name="junit-jupiter-params-5.14.3.jar">
<sha512
value="00367c3b8c02fbe91c07bb889763777eda02a25a88ed9fb8013d00d6c2f9171ea85e4af7a4326859485aa342600c3d90be5be2883f3953280ff184bb7085465a"
origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="org.junit.jupiter" name="junit-jupiter-params"
version="6.0.3">
+ <artifact name="junit-jupiter-params-6.0.3.jar">
+ <sha512
value="bd1215b879f8cb63162c9a219550acf3bbaa143a8161b276812f124af784112a2fd94b6bae983beafd0de7f6d0c36f223727bb41b7d6d87947500b750fffdede"
origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.junit.platform" name="junit-platform-commons"
version="1.14.3">
<artifact name="junit-platform-commons-1.14.3.jar">
<sha512
value="dd9fea9acbd864594c9f750822dcb17d43f6ad37b68bb4a8729f1813d612c177f27efc6b25d983e5195be8aad3482052685b2b9698205730cff35b585114343a"
origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="org.junit.platform" name="junit-platform-commons"
version="6.0.3">
+ <artifact name="junit-platform-commons-6.0.3.jar">
+ <sha512
value="a22154edbf3c277421dc87e924f5cbe7e2807df43a7b14911303d9f578b4cbe1f3dd5123aff2b94cecd5def3a5141710d6c127f58a03f6ace30be5bd3171fd6e"
origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.junit.platform" name="junit-platform-engine"
version="1.14.3">
<artifact name="junit-platform-engine-1.14.3.jar">
<sha512
value="51a681bb853236b618e42c9c7922a035de515bfa217e3d5f1fa917486d0398c0ffb1cc5504a16130ba06976c24a76d213e8676231f1badb19fc2a164c80b92df"
origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="org.junit.platform" name="junit-platform-engine"
version="6.0.3">
+ <artifact name="junit-platform-engine-6.0.3.jar">
+ <sha512
value="0235da442ee6e189a87f06415c97fdbae1146f5a18ba2e0e9fc57a86916fe4ca1ccf883bb8b96730a524179217de88638cdf87ce7c8ba284cd0fe6f79d93f7aa"
origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.junit.platform" name="junit-platform-launcher"
version="1.14.3">
<artifact name="junit-platform-launcher-1.14.3.jar">
<sha512
value="0437a261bfa2c7fc8fcf9b134515073683435db1e810616cd1f45f4bd89cd8c1c7ce98f19c8896d4c3d737fc0f5536ab69e1fdc207fc019ff4f11f10764ec664"
origin="Generated by Gradle"/>
</artifact>
</component>
+ <component group="org.junit.platform" name="junit-platform-launcher"
version="6.0.3">
+ <artifact name="junit-platform-launcher-6.0.3.jar">
+ <sha512
value="f368b25eb2394328994fe587e8dc295e9e677c55c8d7b559d5798a262e22bbe963cdfffdc0879b54acc2ae500a78e17a7b80e0638d5d411a8b6c84fb11fbe4e3"
origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.junit.platform" name="junit-platform-runner"
version="1.14.3">
<artifact name="junit-platform-runner-1.14.3.jar">
<sha512
value="24c808b481faea635868cc6877ebd342e1b9bd06616d3227d41caf26a12bf9042d410fd27f29a25781a35d6d5594eff4748aec40ae610bfe35b842a10269534f"
origin="Generated by Gradle"/>
@@ -2318,6 +2354,12 @@
<sha512
value="70fac02e1de4f655181fd3505ad61968e971edf59d9eff0b26a657dbdd67ebfcf43f6988cf751d7fb6c443d4caa8293ba65bc567f25129eac2fb6e8ed2b293e3"
origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
+ <component group="org.junit.vintage" name="junit-vintage-engine"
version="6.0.3">
+ <artifact name="junit-vintage-engine-6.0.3.jar">
+ <pgp value="FF6E2C001948C5F2F38B0CC385911F425EC61B51"/>
+ <sha512
value="7b0b92cf0a2bfacfd63417288b5dd115b7ddb2f6c128deb7d5045021e86ca0ce89267b56b70048acd0f600d1137350c485f35981cf57ac991755ee66019f4441"
origin="Generated by Gradle"/>
+ </artifact>
+ </component>
<component group="org.jvnet.staxex" name="stax-ex" version="1.8.1">
<artifact name="stax-ex-1.8.1.jar">
<pgp value="04543577D6A9CC626239C50C7ECBD740FF06AEB5"/>
diff --git a/settings.gradle b/settings.gradle
index 908f53e871..07f1735d75 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -75,6 +75,7 @@ def subprojects = [
'groovy-templates',
'groovy-test',
'groovy-test-junit5',
+ 'groovy-test-junit6',
'groovy-testng',
'groovy-toml',
'groovy-typecheckers',
diff --git a/subprojects/groovy-test-junit5/build.gradle
b/subprojects/groovy-test-junit5/build.gradle
index 5bdc1c3e16..b3d17c1e50 100644
--- a/subprojects/groovy-test-junit5/build.gradle
+++ b/subprojects/groovy-test-junit5/build.gradle
@@ -21,6 +21,10 @@ plugins {
id 'org.apache.groovy-library'
}
+groovyLibrary {
+ optionalModule()
+}
+
dependencies {
api rootProject // JUnit5Runner implements GroovyRunner...
api "org.junit.jupiter:junit-jupiter-api:${versions.junit5}", {
@@ -37,5 +41,4 @@ dependencies {
testImplementation "net.jqwik:jqwik-api:${versions.jqwik}"
testRuntimeOnly "net.jqwik:jqwik-engine:${versions.jqwik}"
testImplementation
"org.junit.jupiter:junit-jupiter-params:${versions.junit5}"
- testRuntimeOnly
"org.junit.platform:junit-platform-runner:${versions.junit5Platform}"
}
diff --git a/subprojects/groovy-test-junit5/build.gradle
b/subprojects/groovy-test-junit6/build.gradle
similarity index 77%
copy from subprojects/groovy-test-junit5/build.gradle
copy to subprojects/groovy-test-junit6/build.gradle
index 5bdc1c3e16..6f1c4a3183 100644
--- a/subprojects/groovy-test-junit5/build.gradle
+++ b/subprojects/groovy-test-junit6/build.gradle
@@ -22,20 +22,17 @@ plugins {
}
dependencies {
- api rootProject // JUnit5Runner implements GroovyRunner...
- api "org.junit.jupiter:junit-jupiter-api:${versions.junit5}", {
+ api rootProject // JUnit6Runner implements GroovyRunner...
+ api "org.junit.jupiter:junit-jupiter-api:${versions.junit6}", {
exclude group: 'org.apiguardian', module: 'apiguardian-api'
exclude group: 'org.junit.platform', module: 'junit-platform-commons'
}
- implementation
"org.junit.jupiter:junit-jupiter-engine:${versions.junit5}", {
+ implementation
"org.junit.jupiter:junit-jupiter-engine:${versions.junit6}", {
exclude group: 'org.apiguardian', module: 'apiguardian-api'
}
- implementation
"org.junit.platform:junit-platform-launcher:${versions.junit5Platform}", {
+ implementation
"org.junit.platform:junit-platform-launcher:${versions.junit6}", {
exclude group: 'org.apiguardian', module: 'apiguardian-api'
}
testImplementation projects.groovyTest
- testImplementation "net.jqwik:jqwik-api:${versions.jqwik}"
- testRuntimeOnly "net.jqwik:jqwik-engine:${versions.jqwik}"
- testImplementation
"org.junit.jupiter:junit-jupiter-params:${versions.junit5}"
- testRuntimeOnly
"org.junit.platform:junit-platform-runner:${versions.junit5Platform}"
+ testImplementation
"org.junit.jupiter:junit-jupiter-params:${versions.junit6}"
}
diff --git
a/subprojects/groovy-test-junit6/src/main/groovy/groovy/junit6/plugin/GroovyJUnitRunnerHelper.groovy
b/subprojects/groovy-test-junit6/src/main/groovy/groovy/junit6/plugin/GroovyJUnitRunnerHelper.groovy
new file mode 100644
index 0000000000..06ef0a6288
--- /dev/null
+++
b/subprojects/groovy-test-junit6/src/main/groovy/groovy/junit6/plugin/GroovyJUnitRunnerHelper.groovy
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+package groovy.junit6.plugin
+
+import org.junit.platform.launcher.Launcher
+import org.junit.platform.launcher.LauncherDiscoveryRequest
+import org.junit.platform.launcher.TestExecutionListener
+import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
+import org.junit.platform.launcher.core.LauncherFactory
+import org.junit.platform.launcher.listeners.LoggingListener
+import org.junit.platform.launcher.listeners.SummaryGeneratingListener
+
+import static
org.junit.platform.engine.discovery.DiscoverySelectors.selectClass
+
+class GroovyJUnitRunnerHelper {
+ @SuppressWarnings('Println')
+ static Throwable execute(Class testClass) {
+ LauncherDiscoveryRequest request =
LauncherDiscoveryRequestBuilder.request()
+ .selectors(selectClass(testClass)).build()
+ Launcher launcher = LauncherFactory.create()
+
+ TestExecutionListener listener = new SummaryGeneratingListener()
+ launcher.registerTestExecutionListeners(listener)
+
launcher.registerTestExecutionListeners(LoggingListener.forJavaUtilLogging())
+ launcher.execute(request)
+ println listener.summary.with{ "JUnit6 launcher:
passed=$testsSucceededCount, aborted=$testsAbortedCount,
failed=$testsFailedCount, skipped=$testsSkippedCount,
time=${timeFinished-timeStarted}ms" }
+ if (listener.summary.failures) {
+ listener.summary.printFailuresTo(new PrintWriter(System.out, true))
+ return listener.summary.failures[0].exception
+ }
+ null
+ }
+}
diff --git
a/subprojects/groovy-test-junit6/src/main/java/groovy/junit6/plugin/JUnit6Runner.java
b/subprojects/groovy-test-junit6/src/main/java/groovy/junit6/plugin/JUnit6Runner.java
new file mode 100644
index 0000000000..d372964b10
--- /dev/null
+++
b/subprojects/groovy-test-junit6/src/main/java/groovy/junit6/plugin/JUnit6Runner.java
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+package groovy.junit6.plugin;
+
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyRuntimeException;
+import org.apache.groovy.plugin.GroovyRunner;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Integration code for running JUnit 6 (Jupiter) tests in Groovy.
+ */
+public class JUnit6Runner implements GroovyRunner {
+
+ private static final System.Logger LOGGER =
System.getLogger(JUnit6Runner.class.getName());
+
+ /**
+ * Utility method to check via reflection if the parsed class appears to
be a JUnit Jupiter
+ * test, i.e. checks whether it appears to be using the relevant
annotations.
+ *
+ * @param scriptClass the class we want to check
+ * @param loader the GroovyClassLoader to use to find classes
+ * @return true if the class appears to be a compatible test
+ */
+ @Override
+ public boolean canRun(Class<?> scriptClass, GroovyClassLoader loader) {
+ if (!tryLoadClass("org.junit.jupiter.api.Test", loader)) {
+ return false;
+ }
+ if (isJupiterAnnotationPresent(scriptClass.getAnnotations(), loader)) {
+ return true;
+ }
+ Method[] methods = scriptClass.getMethods();
+ for (Method method : methods) {
+ if (isJupiterAnnotationPresent(method.getAnnotations(), loader)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isJupiterAnnotationPresent(Annotation[] annotations,
GroovyClassLoader loader) {
+ for (Annotation annotation : annotations) {
+ Class<? extends Annotation> type = annotation.annotationType();
+ String name = type.getName();
+ if (name.startsWith("org.junit.jupiter.api.") &&
tryLoadClass(name, loader)) {
+ return true;
+ }
+ // it might directly annotate a class, e.g. Specification in Spock
2
+ if ("org.junit.platform.commons.annotation.Testable".equals(name)
&& tryLoadClass(name, loader)) {
+ return true;
+ }
+ if (isJupiterTestableMetaAnnotationPresent(type, new HashSet<>())
&& tryLoadClass(name, loader)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isJupiterTestableMetaAnnotationPresent(Class<? extends
Annotation> type, Set<String> seen) {
+ for (Annotation annotation : type.getAnnotations()) {
+ // It might annotate an annotation, e.g. jqwik @Property
+ if
("org.junit.platform.commons.annotation.Testable".equals(annotation.annotationType().getName()))
{
+ return true;
+ }
+ // perhaps it's a meta-annotation, e.g. jqwik @Example is
annotated with @Property
+ if (!seen.contains(annotation.annotationType().getName())) {
+ seen.add(annotation.annotationType().getName());
+ if
(isJupiterTestableMetaAnnotationPresent(annotation.annotationType(), seen)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean tryLoadClass(String name, GroovyClassLoader loader) {
+ try {
+ loader.loadClass(name);
+ return true;
+ } catch (ClassNotFoundException ignore) {
+ // fall through
+ }
+ return false;
+ }
+
+ /**
+ * Utility method to run a JUnit 6 test.
+ *
+ * @param scriptClass the class we want to run as a test
+ * @param loader the class loader to use
+ * @return the result of running the test
+ */
+ @Override
+ public Object run(Class<?> scriptClass, GroovyClassLoader loader) {
+ try {
+ try {
+
loader.loadClass("org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder");
+ } catch (ClassNotFoundException ignored) {
+ // subsequent steps will bomb out but try to give some more
friendly information first
+ LOGGER.log(System.Logger.Level.WARNING,
+ "Required dependency:
org.junit.platform:junit-platform-launcher doesn't appear to be on the
classpath");
+ }
+ Class<?> helper =
loader.loadClass("groovy.junit6.plugin.GroovyJUnitRunnerHelper");
+ Throwable ifFailed = (Throwable)
InvokerHelper.invokeStaticMethod(helper, "execute", new Object[]{scriptClass});
+ if (ifFailed != null) {
+ throw new GroovyRuntimeException(ifFailed);
+ }
+ return null;
+ } catch (ClassNotFoundException e) {
+ throw new GroovyRuntimeException("Error running JUnit 6 test.", e);
+ }
+ }
+
+}
diff --git
a/subprojects/groovy-test-junit6/src/main/java/groovy/junit6/plugin/package-info.java
b/subprojects/groovy-test-junit6/src/main/java/groovy/junit6/plugin/package-info.java
new file mode 100644
index 0000000000..4f3f2441a8
--- /dev/null
+++
b/subprojects/groovy-test-junit6/src/main/java/groovy/junit6/plugin/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Classes to support running JUnit 6 (Jupiter) tests as scripts.
+ */
+package groovy.junit6.plugin;
diff --git
a/subprojects/groovy-test-junit6/src/main/resources/META-INF/services/org.apache.groovy.plugin.GroovyRunner
b/subprojects/groovy-test-junit6/src/main/resources/META-INF/services/org.apache.groovy.plugin.GroovyRunner
new file mode 100644
index 0000000000..a1c1717030
--- /dev/null
+++
b/subprojects/groovy-test-junit6/src/main/resources/META-INF/services/org.apache.groovy.plugin.GroovyRunner
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+groovy.junit6.plugin.JUnit6Runner
diff --git a/subprojects/groovy-test-junit6/src/test/groovy/JUnit6Test.groovy
b/subprojects/groovy-test-junit6/src/test/groovy/JUnit6Test.groovy
new file mode 100644
index 0000000000..3afc58c81f
--- /dev/null
+++ b/subprojects/groovy-test-junit6/src/test/groovy/JUnit6Test.groovy
@@ -0,0 +1,60 @@
+/*
+ * 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.junit.jupiter.api.RepeatedTest
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.TestFactory
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.ValueSource
+
+import java.util.stream.Stream
+
+import static org.junit.jupiter.api.Assertions.assertTrue
+import static org.junit.jupiter.api.DynamicTest.dynamicTest
+
+class JUnit6Test {
+
+ @Test
+ void streamSum() {
+ assertTrue(Stream.of(1, 2, 3)
+ .mapToInt(i -> i)
+ .sum() > 5, () -> "Sum should be greater than 5")
+ }
+
+ @RepeatedTest(value = 2, name = "{displayName}
{currentRepetition}/{totalRepetitions}")
+ void streamSumRepeated() {
+ assert Stream.of(1, 2, 3).mapToInt(i -> i).sum() == 6
+ }
+
+ private boolean isPalindrome(s) { s == s.reverse() }
+
+ @ParameterizedTest
+ @ValueSource(strings = ["racecar", "radar", "able was I ere I saw elba"])
+ void palindromes(String candidate) {
+ assert isPalindrome(candidate)
+ }
+
+ @TestFactory
+ def dynamicTestCollection() {
+ [
+ dynamicTest("Add test") { -> assert 1 + 1 == 2 },
+ dynamicTest("Multiply Test", () -> { assert 2 * 3 == 6 })
+ ]
+ }
+}
diff --git a/versions.properties b/versions.properties
index 1ff26f3bee..33e43145b1 100644
--- a/versions.properties
+++ b/versions.properties
@@ -45,6 +45,7 @@ jruby=9.2.17.0
junit=4.13.2
junit5=5.14.3
junit5Platform=1.14.3
+junit6=6.0.3
log4j=1.2.17
log4j2=2.25.3
logback=1.5.32