From 7fb4165c94fb8d9c0e9dfd30519371d3ca73e1fe Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 12 Aug 2023 12:45:59 +0200 Subject: [PATCH 001/142] Improve Javadoc for assertTimeoutPreemptively regarding thread interrupt Closes #3424 --- .../org/junit/jupiter/api/Assertions.java | 91 ++++++++----------- 1 file changed, 37 insertions(+), 54 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assertions.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assertions.java index 4be1561689dc..670f1373fb8d 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assertions.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Assertions.java @@ -59,22 +59,26 @@ *

Preemptive Timeouts

* *

The various {@code assertTimeoutPreemptively()} methods in this class - * execute the provided {@code executable} or {@code supplier} in a different - * thread than that of the calling code. This behavior can lead to undesirable - * side effects if the code that is executed within the {@code executable} or - * {@code supplier} relies on {@link ThreadLocal} storage. + * execute the provided callback ({@code executable} or {@code supplier}) in a + * different thread than that of the calling code. If the timeout is exceeded, + * an attempt will be made to preemptively abort execution of the callback by + * {@linkplain Thread#interrupt() interrupting} the callback's thread. If the + * callback's thread does not return when interrupted, the thread will continue + * to run in the background after the {@code assertTimeoutPreemptively()} method + * has returned. * - *

One common example of this is the transactional testing support in the Spring - * Framework. Specifically, Spring's testing support binds transaction state to - * the current thread (via a {@code ThreadLocal}) before a test method is invoked. - * Consequently, if an {@code executable} or {@code supplier} provided to - * {@code assertTimeoutPreemptively()} invokes Spring-managed components that - * participate in transactions, any actions taken by those components will not be - * rolled back with the test-managed transaction. On the contrary, such actions - * will be committed to the persistent store (e.g., relational database) even - * though the test-managed transaction is rolled back. - * - *

Similar side effects may be encountered with other frameworks that rely on + *

Furthermore, the behavior of {@code assertTimeoutPreemptively()} methods + * can lead to undesirable side effects if the code that is executed within the + * callback relies on {@link ThreadLocal} storage. One common example of this is + * the transactional testing support in the Spring Framework. Specifically, Spring's + * testing support binds transaction state to the current thread (via a + * {@code ThreadLocal}) before a test method is invoked. Consequently, if a + * callback provided to {@code assertTimeoutPreemptively()} invokes Spring-managed + * components that participate in transactions, any actions taken by those + * components will not be rolled back with the test-managed transaction. On the + * contrary, such actions will be committed to the persistent store (e.g., + * relational database) even though the test-managed transaction is rolled back. + * Similar side effects may be encountered with other frameworks that rely on * {@code ThreadLocal} storage. * *

Extensibility

@@ -3410,11 +3414,8 @@ public static T assertTimeout(Duration timeout, ThrowingSupplier supplier * Assert that execution of the supplied {@code executable} * completes before the given {@code timeout} is exceeded. * - *

Note: the {@code executable} will be executed in a different thread than - * that of the calling code. Furthermore, execution of the {@code executable} will - * be preemptively aborted if the timeout is exceeded. See the - * {@linkplain Assertions Preemptive Timeouts} section of the class-level - * Javadoc for a discussion of possible undesirable side effects. + *

See the {@linkplain Assertions Preemptive Timeouts} section of the + * class-level Javadoc for further details. * * @see #assertTimeoutPreemptively(Duration, Executable, String) * @see #assertTimeoutPreemptively(Duration, Executable, Supplier) @@ -3431,11 +3432,8 @@ public static void assertTimeoutPreemptively(Duration timeout, Executable execut * Assert that execution of the supplied {@code executable} * completes before the given {@code timeout} is exceeded. * - *

Note: the {@code executable} will be executed in a different thread than - * that of the calling code. Furthermore, execution of the {@code executable} will - * be preemptively aborted if the timeout is exceeded. See the - * {@linkplain Assertions Preemptive Timeouts} section of the class-level - * Javadoc for a discussion of possible undesirable side effects. + *

See the {@linkplain Assertions Preemptive Timeouts} section of the + * class-level Javadoc for further details. * *

Fails with the supplied failure {@code message}. * @@ -3454,11 +3452,8 @@ public static void assertTimeoutPreemptively(Duration timeout, Executable execut * Assert that execution of the supplied {@code executable} * completes before the given {@code timeout} is exceeded. * - *

Note: the {@code executable} will be executed in a different thread than - * that of the calling code. Furthermore, execution of the {@code executable} will - * be preemptively aborted if the timeout is exceeded. See the - * {@linkplain Assertions Preemptive Timeouts} section of the class-level - * Javadoc for a discussion of possible undesirable side effects. + *

See the {@linkplain Assertions Preemptive Timeouts} section of the + * class-level Javadoc for further details. * *

If necessary, the failure message will be retrieved lazily from the * supplied {@code messageSupplier}. @@ -3481,13 +3476,10 @@ public static void assertTimeoutPreemptively(Duration timeout, Executable execut * Assert that execution of the supplied {@code supplier} * completes before the given {@code timeout} is exceeded. * - *

If the assertion passes then the {@code supplier}'s result is returned. + *

See the {@linkplain Assertions Preemptive Timeouts} section of the + * class-level Javadoc for further details. * - *

Note: the {@code supplier} will be executed in a different thread than - * that of the calling code. Furthermore, execution of the {@code supplier} will - * be preemptively aborted if the timeout is exceeded. See the - * {@linkplain Assertions Preemptive Timeouts} section of the class-level - * Javadoc for a discussion of possible undesirable side effects. + *

If the assertion passes then the {@code supplier}'s result is returned. * * @see #assertTimeoutPreemptively(Duration, Executable) * @see #assertTimeoutPreemptively(Duration, Executable, String) @@ -3504,13 +3496,10 @@ public static T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier * Assert that execution of the supplied {@code supplier} * completes before the given {@code timeout} is exceeded. * - *

If the assertion passes then the {@code supplier}'s result is returned. + *

See the {@linkplain Assertions Preemptive Timeouts} section of the + * class-level Javadoc for further details. * - *

Note: the {@code supplier} will be executed in a different thread than - * that of the calling code. Furthermore, execution of the {@code supplier} will - * be preemptively aborted if the timeout is exceeded. See the - * {@linkplain Assertions Preemptive Timeouts} section of the class-level - * Javadoc for a discussion of possible undesirable side effects. + *

If the assertion passes then the {@code supplier}'s result is returned. * *

Fails with the supplied failure {@code message}. * @@ -3529,13 +3518,10 @@ public static T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier * Assert that execution of the supplied {@code supplier} * completes before the given {@code timeout} is exceeded. * - *

If the assertion passes then the {@code supplier}'s result is returned. + *

See the {@linkplain Assertions Preemptive Timeouts} section of the + * class-level Javadoc for further details. * - *

Note: the {@code supplier} will be executed in a different thread than - * that of the calling code. Furthermore, execution of the {@code supplier} will - * be preemptively aborted if the timeout is exceeded. See the - * {@linkplain Assertions Preemptive Timeouts} section of the class-level - * Javadoc for a discussion of possible undesirable side effects. + *

If the assertion passes then the {@code supplier}'s result is returned. * *

If necessary, the failure message will be retrieved lazily from the * supplied {@code messageSupplier}. @@ -3556,18 +3542,15 @@ public static T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier * Assert that execution of the supplied {@code supplier} * completes before the given {@code timeout} is exceeded. * + *

See the {@linkplain Assertions Preemptive Timeouts} section of the + * class-level Javadoc for further details. + * *

If the assertion passes then the {@code supplier}'s result is returned. * *

In the case the assertion does not pass, the supplied * {@link TimeoutFailureFactory} is invoked to create an exception which is * then thrown. * - *

Note: the {@code supplier} will be executed in a different thread than - * that of the calling code. Furthermore, execution of the {@code supplier} will - * be preemptively aborted if the timeout is exceeded. See the - * {@linkplain Assertions Preemptive Timeouts} section of the class-level - * Javadoc for a discussion of possible undesirable side effects. - * *

If necessary, the failure message will be retrieved lazily from the * supplied {@code messageSupplier}. * From 4eca30b4fb8e79cb134d01c22556827e1563ef75 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Thu, 17 Aug 2023 16:15:20 +0200 Subject: [PATCH 002/142] Polishing --- .../org/junit/platform/console/ConsoleLauncherTests.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java index b56c5dd1be42..80ec67b578a1 100644 --- a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java +++ b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java @@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.params.provider.Arguments.arguments; import java.io.PrintWriter; import java.io.StringWriter; @@ -81,9 +82,9 @@ void executeWithoutCommandLineOptions(String command, int expectedExitCode) { static Stream commandsWithEmptyOptionExitCodes() { return Stream.of( // - Arguments.of("execute", -1), // - Arguments.of("discover", -1), // - Arguments.of("engines", 0) // + arguments("execute", -1), // + arguments("discover", -1), // + arguments("engines", 0) // ); } From bc862e01288a8392992c32c03dd8f25cb1b6023f Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Thu, 17 Aug 2023 16:17:10 +0200 Subject: [PATCH 003/142] Avoid NullPointerExceptions in console output in tests Prior to this commit, the following types of NullPointerExceptions were overlooked in the console output. java.lang.NullPointerException: Cannot invoke "org.junit.platform.console.tasks.ConsoleTestExecutor.execute(java.io.PrintWriter, java.util.Optional)" because the return value of "org.junit.platform.console.tasks.ConsoleTestExecutor$Factory.create(org.junit.platform.console.options.TestDiscoveryOptions, org.junit.platform.console.options.TestConsoleOutputOptions)" is null Although the NullPointerExceptions did not cause the tests to fail, this commit updates the tests to avoid them anyway. --- .../org/junit/platform/console/ConsoleLauncherTests.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java index 80ec67b578a1..00fed18c5351 100644 --- a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java +++ b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java @@ -34,17 +34,17 @@ class ConsoleLauncherTests { @ParameterizedTest(name = "{0}") @MethodSource("commandsWithEmptyOptionExitCodes") void displayHelp(String command) { - var consoleLauncher = new ConsoleLauncher((__, ___) -> null, printSink, printSink); + var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink); var exitCode = consoleLauncher.run(command, "--help").getExitCode(); assertEquals(0, exitCode); - assertThat(stringWriter.toString()).contains("--help"); + assertThat(stringWriter.toString()).contains("--help", "--disable-banner", "--scan-classpath" /* ... */); } @ParameterizedTest(name = "{0}") @MethodSource("commandsWithEmptyOptionExitCodes") void displayBanner(String command) { - var consoleLauncher = new ConsoleLauncher((__, ___) -> null, printSink, printSink); + var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink); consoleLauncher.run(command); assertThat(stringWriter.toString()).contains( @@ -54,7 +54,7 @@ void displayBanner(String command) { @ParameterizedTest(name = "{0}") @MethodSource("commandsWithEmptyOptionExitCodes") void disableBanner(String command, int expectedExitCode) { - var consoleLauncher = new ConsoleLauncher((__, ___) -> null, printSink, printSink); + var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink); var exitCode = consoleLauncher.run(command, "--disable-banner").getExitCode(); assertEquals(expectedExitCode, exitCode); From 9a9063d428151e35f95e661b442e057f468d9e89 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Thu, 17 Aug 2023 16:41:27 +0200 Subject: [PATCH 004/142] Fix failing test in ConsoleLauncherTests --- .../java/org/junit/platform/console/ConsoleLauncherTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java index 00fed18c5351..37d9c9349a73 100644 --- a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java +++ b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java @@ -38,7 +38,7 @@ void displayHelp(String command) { var exitCode = consoleLauncher.run(command, "--help").getExitCode(); assertEquals(0, exitCode); - assertThat(stringWriter.toString()).contains("--help", "--disable-banner", "--scan-classpath" /* ... */); + assertThat(stringWriter.toString()).contains("--help", "--disable-banner" /* ... */); } @ParameterizedTest(name = "{0}") From e0621f5993b03c84e6e197dfc840178bf698011e Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 25 Aug 2023 10:54:46 +0200 Subject: [PATCH 005/142] Fix implementation of RandomNumberExtension in the User Guide Closes #3433 --- .../src/test/java/example/extensions/RandomNumberExtension.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/test/java/example/extensions/RandomNumberExtension.java b/documentation/src/test/java/example/extensions/RandomNumberExtension.java index 3bbece08e206..b2a900dc5ea5 100644 --- a/documentation/src/test/java/example/extensions/RandomNumberExtension.java +++ b/documentation/src/test/java/example/extensions/RandomNumberExtension.java @@ -86,7 +86,7 @@ private void injectFields(Class testClass, Object testInstance, } private static boolean isInteger(Class type) { - return int.class.isAssignableFrom(type); + return type == Integer.class || type == int.class; } } From 548fb693ad00a924a71e04d07c5f90b4f5d84014 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Mon, 28 Aug 2023 11:17:00 +0200 Subject: [PATCH 006/142] Disable Picocli's usage help auto width computation Fixes #3419 --- .../java/org/junit/platform/console/options/MainCommand.java | 2 +- .../java/org/junit/platform/console/ConsoleLauncherTests.java | 3 +-- .../java/platform/tooling/support/tests/StandaloneTests.java | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java b/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java index 610094564b9e..284ff655b168 100644 --- a/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java +++ b/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java @@ -33,7 +33,7 @@ sortOptions = false, // usageHelpWidth = 95, // showAtFileInUsageHelp = true, // - usageHelpAutoWidth = true, // + usageHelpAutoWidth = false, // https://github.com/remkop/picocli/issues/1104 description = "Launches the JUnit Platform for test discovery and execution.", // footerHeading = "%n", // footer = "For more information, please refer to the JUnit User Guide at%n" // diff --git a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java index 37d9c9349a73..70e6bd21d536 100644 --- a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java +++ b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherTests.java @@ -47,8 +47,7 @@ void displayBanner(String command) { var consoleLauncher = new ConsoleLauncher(ConsoleTestExecutor::new, printSink, printSink); consoleLauncher.run(command); - assertThat(stringWriter.toString()).contains( - "Thanks for using JUnit! Support its development at https://junit.org/sponsoring"); + assertThat(stringWriter.toString()).contains("Thanks for using JUnit!"); } @ParameterizedTest(name = "{0}") diff --git a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java index eb8eb20254f2..3b9f4524b680 100644 --- a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java +++ b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java @@ -66,7 +66,7 @@ void listAllObservableEngines() { .setTool(new Java()) // .setProject("standalone") // .addArguments("-jar", MavenRepo.jar("junit-platform-console-standalone")) // - .addArguments("engines", "--disable-banner").build() // + .addArguments("engines", "--disable-ansi-colors", "--disable-banner").build() // .run(false); assertEquals(0, result.getExitCode(), String.join("\n", result.getOutputLines("out"))); From 50d1d4d86037e6381a12517ddaf540862e23e97e Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Tue, 29 Aug 2023 07:15:27 +0200 Subject: [PATCH 007/142] Update picocli to 4.7.5 and enable help width computation --- gradle/libs.versions.toml | 2 +- .../java/org/junit/platform/console/options/MainCommand.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e09185b07577..e0d997838ba5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -57,7 +57,7 @@ mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.4.0" } opentest4j = { module = "org.opentest4j:opentest4j", version.ref = "opentest4j" } openTestReporting-events = { module = "org.opentest4j.reporting:open-test-reporting-events", version.ref = "openTestReporting" } openTestReporting-tooling = { module = "org.opentest4j.reporting:open-test-reporting-tooling", version.ref = "openTestReporting" } -picocli = { module = "info.picocli:picocli", version = "4.7.4" } +picocli = { module = "info.picocli:picocli", version = "4.7.5" } slf4j-julBinding = { module = "org.slf4j:slf4j-jdk14", version = "2.0.7" } spock1 = { module = "org.spockframework:spock-core", version = "1.3-groovy-2.5" } univocity-parsers = { module = "com.univocity:univocity-parsers", version = "2.9.1" } diff --git a/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java b/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java index 284ff655b168..610094564b9e 100644 --- a/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java +++ b/junit-platform-console/src/main/java/org/junit/platform/console/options/MainCommand.java @@ -33,7 +33,7 @@ sortOptions = false, // usageHelpWidth = 95, // showAtFileInUsageHelp = true, // - usageHelpAutoWidth = false, // https://github.com/remkop/picocli/issues/1104 + usageHelpAutoWidth = true, // description = "Launches the JUnit Platform for test discovery and execution.", // footerHeading = "%n", // footer = "For more information, please refer to the JUnit User Guide at%n" // From e7c873cdf2f2bb6702145094e05ce6750eaa11bf Mon Sep 17 00:00:00 2001 From: JUnit Builds Date: Fri, 1 Sep 2023 17:53:40 +0200 Subject: [PATCH 008/142] Bump Gradle Wrapper from 8.3-rc-2 to 8.3 (#3429) --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b62cae5b21db..864d6c47512b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=222818637ce0a4cb82e322bf847ea49ac319aecdb363d81acabd9e81315d08f6 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-rc-2-bin.zip +distributionSha256Sum=591855b517fc635b9e04de1d05d5e76ada3f89f5fc76f87978d1b245b4f69225 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From ca38085dcd7fba32b1693eac15bee77a0bb3d53f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Sep 2023 11:11:56 +0000 Subject: [PATCH 009/142] Bump com.puppycrawl.tools:checkstyle from 10.12.1 to 10.12.3 Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 10.12.1 to 10.12.3. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.1...checkstyle-10.12.3) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e0d997838ba5..aa98393851de 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ asciidoctor-pdf = "1.5.3" asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gradle.kts can be removed when upgrading assertj = "3.24.2" bnd = "6.4.0" -checkstyle = "10.12.1" +checkstyle = "10.12.3" gradleVersionsPlugin = "0.47.0" jacoco = "0.8.7" jmh = "1.36" From 171c61cc035ff12ebd117ba8adbc88c198340912 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 05:36:22 +0000 Subject: [PATCH 010/142] Bump com.tngtech.archunit:archunit-junit5 from 1.0.1 to 1.1.0 Bumps [com.tngtech.archunit:archunit-junit5](https://github.com/TNG/ArchUnit) from 1.0.1 to 1.1.0. - [Release notes](https://github.com/TNG/ArchUnit/releases) - [Commits](https://github.com/TNG/ArchUnit/compare/v1.0.1...v1.1.0) --- updated-dependencies: - dependency-name: com.tngtech.archunit:archunit-junit5 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aa98393851de..3ab2376f7982 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ ant = { module = "org.apache.ant:ant", version.ref = "ant" } ant-junit = { module = "org.apache.ant:ant-junit", version.ref = "ant" } ant-junitlauncher = { module = "org.apache.ant:ant-junitlauncher", version.ref = "ant" } apiguardian = { module = "org.apiguardian:apiguardian-api", version.ref = "apiguardian" } -archunit = { module = "com.tngtech.archunit:archunit-junit5", version = "1.0.1" } +archunit = { module = "com.tngtech.archunit:archunit-junit5", version = "1.1.0" } assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } From a6a559b69ea182bc85494ca10549f34425910126 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 5 Sep 2023 13:50:55 +0200 Subject: [PATCH 011/142] Create empty release notes for 5.10.1 from template --- .../docs/asciidoc/release-notes/index.adoc | 2 + .../release-notes/release-notes-5.10.1.adoc | 58 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc diff --git a/documentation/src/docs/asciidoc/release-notes/index.adoc b/documentation/src/docs/asciidoc/release-notes/index.adoc index 800b74226ff8..952c742a86d3 100644 --- a/documentation/src/docs/asciidoc/release-notes/index.adoc +++ b/documentation/src/docs/asciidoc/release-notes/index.adoc @@ -18,4 +18,6 @@ include::{includedir}/link-attributes.adoc[] include::{basedir}/release-notes-5.11.0-M1.adoc[] +include::{basedir}/release-notes-5.10.1.adoc[] + include::{basedir}/release-notes-5.10.0.adoc[] diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc new file mode 100644 index 000000000000..f9e994b0bd79 --- /dev/null +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -0,0 +1,58 @@ +[[release-notes-5.10.1]] +== 5.10.1 + +*Date of Release:* ❓ + +*Scope:* ❓ + +For a complete list of all _closed_ issues and pull requests for this release, consult the +link:{junit5-repo}+/milestone/72?closed=1+[5.10.1] milestone page in the +JUnit repository on GitHub. + + +[[release-notes-5.10.1-junit-platform]] +=== JUnit Platform + +==== Bug Fixes + +* ❓ + +==== Deprecations and Breaking Changes + +* ❓ + +==== New Features and Improvements + +* ❓ + + +[[release-notes-5.10.1-junit-jupiter]] +=== JUnit Jupiter + +==== Bug Fixes + +* ❓ + +==== Deprecations and Breaking Changes + +* ❓ + +==== New Features and Improvements + +* ❓ + + +[[release-notes-5.10.1-junit-vintage]] +=== JUnit Vintage + +==== Bug Fixes + +* ❓ + +==== Deprecations and Breaking Changes + +* ❓ + +==== New Features and Improvements + +* ❓ From cb3445283961678a18ada304d7a33aba4cc6736d Mon Sep 17 00:00:00 2001 From: Pavlo Shevchenko Date: Tue, 5 Sep 2023 15:26:27 +0200 Subject: [PATCH 012/142] Fix reporting of ignored JUnit 3 test classes (#3427) Prior to this commit, `@Ignore`-annotated JUnit 3 test classes where reported as started and then as skipped due to their `Description` not including class-level annotations in some case. Co-authored-by: Marc Philipp --- .../release-notes/release-notes-5.10.1.adoc | 2 +- .../descriptor/RunnerTestDescriptor.java | 8 +++++- .../discovery/ClassSelectorResolver.java | 5 ++-- ...fensiveAllDefaultPossibilitiesBuilder.java | 6 +++- .../engine/execution/RunListenerAdapter.java | 25 +++++++++++++---- .../VintageTestEngineExecutionTests.java | 24 ++++++++++++++++ .../engine/execution/TestRunTests.java | 6 ++-- .../samples/junit3/IgnoredJUnit3TestCase.java | 28 +++++++++++++++++++ .../JUnit4SuiteWithIgnoredJUnit3TestCase.java | 20 +++++++++++++ 9 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java create mode 100644 junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit4SuiteWithIgnoredJUnit3TestCase.java diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc index f9e994b0bd79..f3186db2b66a 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -47,7 +47,7 @@ JUnit repository on GitHub. ==== Bug Fixes -* ❓ +* Fix reporting of JUnit 3 test classes with `@Ignored` annotation ==== Deprecations and Breaking Changes diff --git a/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerTestDescriptor.java b/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerTestDescriptor.java index 0ad3c5f9b6a0..03ae08dd0a6c 100644 --- a/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerTestDescriptor.java +++ b/junit-vintage-engine/src/main/java/org/junit/vintage/engine/descriptor/RunnerTestDescriptor.java @@ -43,12 +43,14 @@ public class RunnerTestDescriptor extends VintageTestDescriptor { private final Set rejectedExclusions = new HashSet<>(); private Runner runner; + private final boolean ignored; private boolean wasFiltered; private List filters = new ArrayList<>(); - public RunnerTestDescriptor(UniqueId uniqueId, Class testClass, Runner runner) { + public RunnerTestDescriptor(UniqueId uniqueId, Class testClass, Runner runner, boolean ignored) { super(uniqueId, runner.getDescription(), testClass.getSimpleName(), ClassSource.from(testClass)); this.runner = runner; + this.ignored = ignored; } @Override @@ -155,6 +157,10 @@ private Runner getRunnerToReport() { return (runner instanceof RunnerDecorator) ? ((RunnerDecorator) runner).getDecoratedRunner() : runner; } + public boolean isIgnored() { + return ignored; + } + private static class ExcludeDescriptionFilter extends Filter { private final Description description; diff --git a/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/ClassSelectorResolver.java b/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/ClassSelectorResolver.java index a2d1e7d4c80c..14445f155b4e 100644 --- a/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/ClassSelectorResolver.java +++ b/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/ClassSelectorResolver.java @@ -26,7 +26,6 @@ import org.junit.platform.engine.discovery.UniqueIdSelector; import org.junit.platform.engine.support.discovery.SelectorResolver; import org.junit.runner.Runner; -import org.junit.runners.model.RunnerBuilder; import org.junit.vintage.engine.descriptor.RunnerTestDescriptor; /** @@ -34,7 +33,7 @@ */ class ClassSelectorResolver implements SelectorResolver { - private static final RunnerBuilder RUNNER_BUILDER = new DefensiveAllDefaultPossibilitiesBuilder(); + private static final DefensiveAllDefaultPossibilitiesBuilder RUNNER_BUILDER = new DefensiveAllDefaultPossibilitiesBuilder(); private final ClassFilter classFilter; @@ -76,7 +75,7 @@ private Resolution resolveTestClass(Class testClass, Context context) { private RunnerTestDescriptor createRunnerTestDescriptor(TestDescriptor parent, Class testClass, Runner runner) { UniqueId uniqueId = parent.getUniqueId().append(SEGMENT_TYPE_RUNNER, testClass.getName()); - return new RunnerTestDescriptor(uniqueId, testClass, runner); + return new RunnerTestDescriptor(uniqueId, testClass, runner, RUNNER_BUILDER.isIgnored(runner)); } } diff --git a/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java b/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java index 0da94f689fde..b35dc20077c4 100644 --- a/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java +++ b/junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java @@ -64,6 +64,10 @@ public Runner runnerForClass(Class testClass) throws Throwable { return runner; } + boolean isIgnored(Runner runner) { + return runner instanceof IgnoredClassRunner || runner instanceof IgnoringRunnerDecorator; + } + /** * Instead of checking for the {@link Ignore} annotation and returning an * {@link IgnoredClassRunner} from {@link IgnoredBuilder}, we've let the @@ -72,7 +76,7 @@ public Runner runnerForClass(Class testClass) throws Throwable { * override its runtime behavior (i.e. skip execution) but return its * regular {@link org.junit.runner.Description}. */ - private Runner decorateIgnoredTestClass(Runner runner) { + private IgnoringRunnerDecorator decorateIgnoredTestClass(Runner runner) { if (runner instanceof Filterable) { return new FilterableIgnoringRunnerDecorator(runner); } diff --git a/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunListenerAdapter.java b/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunListenerAdapter.java index 9cefb8faee30..58144877d04a 100644 --- a/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunListenerAdapter.java +++ b/junit-vintage-engine/src/main/java/org/junit/vintage/engine/execution/RunListenerAdapter.java @@ -20,6 +20,7 @@ import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.UniqueId; +import org.junit.platform.engine.support.descriptor.ClassSource; import org.junit.runner.Description; import org.junit.runner.Result; import org.junit.runner.notification.Failure; @@ -49,7 +50,7 @@ class RunListenerAdapter extends RunListener { @Override public void testRunStarted(Description description) { - if (description.isSuite() && description.getAnnotation(Ignore.class) == null) { + if (description.isSuite() && !testRun.getRunnerTestDescriptor().isIgnored()) { fireExecutionStarted(testRun.getRunnerTestDescriptor(), EventType.REPORTED); } } @@ -65,7 +66,9 @@ public void testSuiteStarted(Description description) { @Override public void testIgnored(Description description) { - testIgnored(lookupOrRegisterNextTestDescriptor(description), determineReasonForIgnoredTest(description)); + TestDescriptor testDescriptor = lookupOrRegisterNextTestDescriptor(description); + String reason = determineReasonForIgnoredTest(testDescriptor, description).orElse(""); + testIgnored(testDescriptor, reason); } @Override @@ -176,9 +179,21 @@ private void testIgnored(TestDescriptor testDescriptor, String reason) { fireExecutionSkipped(testDescriptor, reason); } - private String determineReasonForIgnoredTest(Description description) { - Ignore ignoreAnnotation = description.getAnnotation(Ignore.class); - return Optional.ofNullable(ignoreAnnotation).map(Ignore::value).orElse(""); + private Optional determineReasonForIgnoredTest(TestDescriptor testDescriptor, Description description) { + Optional reason = getReason(description.getAnnotation(Ignore.class)); + if (reason.isPresent()) { + return reason; + } + // Workaround for some runners (e.g. JUnit38ClassRunner) don't include the @Ignore annotation + // in the description, so we read it from the test class directly + return testDescriptor.getSource() // + .filter(ClassSource.class::isInstance) // + .map(source -> ((ClassSource) source).getJavaClass()) // + .flatMap(testClass -> getReason(testClass.getAnnotation(Ignore.class))); + } + + private static Optional getReason(Ignore annotation) { + return Optional.ofNullable(annotation).map(Ignore::value); } private void dynamicTestRegistered(TestDescriptor testDescriptor) { diff --git a/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java b/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java index 66af815aff99..cd33b52e2269 100644 --- a/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java +++ b/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java @@ -10,6 +10,7 @@ package org.junit.vintage.engine; +import static java.util.function.Predicate.isEqual; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assumptions.assumeTrue; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; @@ -56,8 +57,10 @@ import org.junit.runner.notification.RunNotifier; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; +import org.junit.vintage.engine.samples.junit3.IgnoredJUnit3TestCase; import org.junit.vintage.engine.samples.junit3.JUnit3ParallelSuiteWithSubsuites; import org.junit.vintage.engine.samples.junit3.JUnit3SuiteWithSubsuites; +import org.junit.vintage.engine.samples.junit3.JUnit4SuiteWithIgnoredJUnit3TestCase; import org.junit.vintage.engine.samples.junit3.PlainJUnit3TestCaseWithSingleTestWhichFails; import org.junit.vintage.engine.samples.junit4.CompletelyDynamicTestCase; import org.junit.vintage.engine.samples.junit4.EmptyIgnoredTestCase; @@ -896,6 +899,27 @@ void executesRegularSpockFeatureMethod() { event(engine(), finishedSuccessfully())); } + @Test + void executesIgnoredJUnit3TestCase() { + var suiteClass = IgnoredJUnit3TestCase.class; + execute(suiteClass).allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(suiteClass), skippedWithReason(isEqual("testing"))), // + event(engine(), finishedSuccessfully())); + } + + @Test + void executesJUnit4SuiteWithIgnoredJUnit3TestCase() { + var suiteClass = JUnit4SuiteWithIgnoredJUnit3TestCase.class; + var testClass = IgnoredJUnit3TestCase.class; + execute(suiteClass).allEvents().assertEventsMatchExactly( // + event(engine(), started()), // + event(container(suiteClass), started()), // + event(container(testClass), skippedWithReason(isEqual("testing"))), // + event(container(suiteClass), finishedSuccessfully()), // + event(engine(), finishedSuccessfully())); + } + private static EngineExecutionResults execute(Class testClass) { return execute(request(testClass)); } diff --git a/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/TestRunTests.java b/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/TestRunTests.java index 69272fd511db..918e32dffa96 100644 --- a/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/TestRunTests.java +++ b/junit-vintage-engine/src/test/java/org/junit/vintage/engine/execution/TestRunTests.java @@ -32,7 +32,8 @@ class TestRunTests { void returnsEmptyOptionalForUnknownDescriptions() throws Exception { Class testClass = PlainJUnit4TestCaseWithSingleTestWhichFails.class; var runnerId = engineId().append(SEGMENT_TYPE_RUNNER, testClass.getName()); - var runnerTestDescriptor = new RunnerTestDescriptor(runnerId, testClass, new BlockJUnit4ClassRunner(testClass)); + var runnerTestDescriptor = new RunnerTestDescriptor(runnerId, testClass, new BlockJUnit4ClassRunner(testClass), + false); var unknownDescription = createTestDescription(testClass, "dynamicTest"); var testRun = new TestRun(runnerTestDescriptor); @@ -45,7 +46,8 @@ void returnsEmptyOptionalForUnknownDescriptions() throws Exception { void registersDynamicTestDescriptors() throws Exception { Class testClass = PlainJUnit4TestCaseWithSingleTestWhichFails.class; var runnerId = engineId().append(SEGMENT_TYPE_RUNNER, testClass.getName()); - var runnerTestDescriptor = new RunnerTestDescriptor(runnerId, testClass, new BlockJUnit4ClassRunner(testClass)); + var runnerTestDescriptor = new RunnerTestDescriptor(runnerId, testClass, new BlockJUnit4ClassRunner(testClass), + false); var dynamicTestId = runnerId.append(SEGMENT_TYPE_DYNAMIC, "dynamicTest"); var dynamicDescription = createTestDescription(testClass, "dynamicTest"); var dynamicTestDescriptor = new VintageTestDescriptor(dynamicTestId, dynamicDescription, null); diff --git a/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java b/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java new file mode 100644 index 000000000000..64015bf57d52 --- /dev/null +++ b/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java @@ -0,0 +1,28 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.vintage.engine.samples.junit3; + +import junit.framework.TestCase; + +import org.junit.Assert; +import org.junit.Ignore; + +/** + * @since 4.12 + */ +@Ignore("testing") +public class IgnoredJUnit3TestCase extends TestCase { + + public void test() { + Assert.fail("this test should be ignored"); + } + +} diff --git a/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit4SuiteWithIgnoredJUnit3TestCase.java b/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit4SuiteWithIgnoredJUnit3TestCase.java new file mode 100644 index 000000000000..ba89153ace0c --- /dev/null +++ b/junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/JUnit4SuiteWithIgnoredJUnit3TestCase.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.vintage.engine.samples.junit3; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ IgnoredJUnit3TestCase.class }) +public class JUnit4SuiteWithIgnoredJUnit3TestCase { +} From 4d8e306535f80e30a06e3862a5c2fef2f95deb54 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 10 Sep 2023 11:52:42 +0200 Subject: [PATCH 013/142] Make closing CloseablePath idempotent Related issue: #3452 --- .../platform/commons/util/CloseablePath.java | 31 ++++-- .../commons/util/CloseablePathTests.java | 96 +++++++++++++++++++ 2 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java index e6bb3ddd27df..58ad17ce39c7 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java @@ -23,6 +23,7 @@ import java.nio.file.Paths; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; @@ -32,7 +33,7 @@ final class CloseablePath implements Closeable { private static final String FILE_URI_SCHEME = "file"; - private static final String JAR_URI_SCHEME = "jar"; + static final String JAR_URI_SCHEME = "jar"; private static final String JAR_FILE_EXTENSION = ".jar"; private static final String JAR_URI_SEPARATOR = "!"; @@ -41,26 +42,34 @@ final class CloseablePath implements Closeable { private static final ConcurrentMap MANAGED_FILE_SYSTEMS = new ConcurrentHashMap<>(); + private final AtomicBoolean closed = new AtomicBoolean(); + private final Path path; private final Closeable delegate; static CloseablePath create(URI uri) throws URISyntaxException { + return create(uri, it -> FileSystems.newFileSystem(it, emptyMap())); + } + + static CloseablePath create(URI uri, FileSystemProvider fileSystemProvider) throws URISyntaxException { if (JAR_URI_SCHEME.equals(uri.getScheme())) { String[] parts = uri.toString().split(JAR_URI_SEPARATOR); String jarUri = parts[0]; String jarEntry = parts[1]; - return createForJarFileSystem(new URI(jarUri), fileSystem -> fileSystem.getPath(jarEntry)); + return createForJarFileSystem(new URI(jarUri), fileSystem -> fileSystem.getPath(jarEntry), + fileSystemProvider); } if (uri.getScheme().equals(FILE_URI_SCHEME) && uri.getPath().endsWith(JAR_FILE_EXTENSION)) { return createForJarFileSystem(new URI(JAR_URI_SCHEME + ':' + uri), - fileSystem -> fileSystem.getRootDirectories().iterator().next()); + fileSystem -> fileSystem.getRootDirectories().iterator().next(), fileSystemProvider); } return new CloseablePath(Paths.get(uri), NULL_CLOSEABLE); } - private static CloseablePath createForJarFileSystem(URI jarUri, Function pathProvider) { + private static CloseablePath createForJarFileSystem(URI jarUri, Function pathProvider, + FileSystemProvider fileSystemProvider) { ManagedFileSystem managedFileSystem = MANAGED_FILE_SYSTEMS.compute(jarUri, - (__, oldValue) -> oldValue == null ? new ManagedFileSystem(jarUri) : oldValue.retain()); + (__, oldValue) -> oldValue == null ? new ManagedFileSystem(jarUri, fileSystemProvider) : oldValue.retain()); Path path = pathProvider.apply(managedFileSystem.fileSystem); return new CloseablePath(path, () -> MANAGED_FILE_SYSTEMS.compute(jarUri, (__, ___) -> managedFileSystem.release())); @@ -77,7 +86,9 @@ public Path getPath() { @Override public void close() throws IOException { - delegate.close(); + if (closed.compareAndSet(false, true)) { + delegate.close(); + } } private static class ManagedFileSystem { @@ -86,10 +97,10 @@ private static class ManagedFileSystem { private final FileSystem fileSystem; private final URI jarUri; - ManagedFileSystem(URI jarUri) { + ManagedFileSystem(URI jarUri, FileSystemProvider fileSystemProvider) { this.jarUri = jarUri; try { - fileSystem = FileSystems.newFileSystem(jarUri, emptyMap()); + fileSystem = fileSystemProvider.newFileSystem(jarUri); } catch (IOException e) { throw new UncheckedIOException("Failed to create file system for " + jarUri, e); @@ -118,4 +129,8 @@ private void close() { } } } + + interface FileSystemProvider { + FileSystem newFileSystem(URI uri) throws IOException; + } } diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java new file mode 100644 index 000000000000..395a895153ed --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java @@ -0,0 +1,96 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.platform.commons.test.ConcurrencyTestingUtils.executeConcurrently; +import static org.junit.platform.commons.util.CloseablePath.JAR_URI_SCHEME; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.only; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.net.URI; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.platform.commons.util.CloseablePath.FileSystemProvider; +import org.junit.platform.engine.support.hierarchical.OpenTest4JAwareThrowableCollector; + +class CloseablePathTests { + + URI uri; + URI jarUri; + + List paths = new ArrayList<>(); + + @BeforeEach + void createUris() throws Exception { + uri = getClass().getResource("/jartest.jar").toURI(); + jarUri = URI.create(JAR_URI_SCHEME + ':' + uri); + } + + @AfterEach + void closeAllPaths() { + closeAll(paths); + } + + @Test + void createsAndClosesJarFileSystemOnceWhenCalledConcurrently() throws Exception { + var numThreads = 50; + + FileSystemProvider fileSystemProvider = mock(); + when(fileSystemProvider.newFileSystem(any())) // + .thenAnswer(invocation -> FileSystems.newFileSystem((URI) invocation.getArgument(0), Map.of())); + + paths = executeConcurrently(numThreads, () -> CloseablePath.create(uri, fileSystemProvider)); + verify(fileSystemProvider, only()).newFileSystem(jarUri); + + // Close all but the first path + closeAll(paths.subList(1, numThreads)); + assertDoesNotThrow(() -> FileSystems.getFileSystem(jarUri), "FileSystem should still be open"); + + // Close last remaining path + paths.get(0).close(); + assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), + "FileSystem should have been closed"); + } + + @Test + void closingIsIdempotent() throws Exception { + var path1 = CloseablePath.create(uri); + paths.add(path1); + var path2 = CloseablePath.create(uri); + paths.add(path2); + + path1.close(); + path1.close(); + assertDoesNotThrow(() -> FileSystems.getFileSystem(jarUri), "FileSystem should still be open"); + + path2.close(); + assertThrows(FileSystemNotFoundException.class, () -> FileSystems.getFileSystem(jarUri), + "FileSystem should have been closed"); + } + + private static void closeAll(List paths) { + var throwableCollector = new OpenTest4JAwareThrowableCollector(); + paths.forEach(closeablePath -> throwableCollector.execute(closeablePath::close)); + throwableCollector.assertEmpty(); + } +} From 0d6dca6c5e08b2d1ac0e3c594b571810d9a52b95 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 10 Sep 2023 12:48:11 +0200 Subject: [PATCH 014/142] Add support for JDK22 env var for Gradle toolchains --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 9de53c4570a6..65cc27143d99 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,7 +21,7 @@ org.gradle.jvmargs=-Xmx1g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryEr --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED org.gradle.caching=true org.gradle.parallel=true -org.gradle.java.installations.fromEnv=JDK8,JDK18,JDK19,JDK20,JDK21 +org.gradle.java.installations.fromEnv=JDK8,JDK18,JDK19,JDK20,JDK21,JDK22 org.gradle.kotlin.dsl.allWarningsAsErrors=true # Test Distribution From 7da21dd0052a0a34afabaf01394adebbc4db489b Mon Sep 17 00:00:00 2001 From: Andrei Rybak Date: Sun, 6 Aug 2023 19:27:17 +0200 Subject: [PATCH 015/142] Drop misleading messages in StandaloneTests Test `execute()` in StandaloneTests asserts matching of lines between expected standard output and actual output lines. It also passes the same actual lines (but in a `String` form) as a message to method assertLinesMatch, which takes three arguments. Same situation for standard error. Drop this confusing argument from the two calls to assertLinesMatch and let class `AssertLinesMatch` construct the error message for us. --- .../java/platform/tooling/support/tests/StandaloneTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java index 3b9f4524b680..de76e04ef91b 100644 --- a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java +++ b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java @@ -354,8 +354,8 @@ void execute() throws IOException { var workspace = Request.WORKSPACE.resolve("standalone"); var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); var expectedErrLines = Files.readAllLines(workspace.resolve("expected-err.txt")); - assertLinesMatch(expectedOutLines, result.getOutputLines("out"), result.getOutput("out")); - assertLinesMatch(expectedErrLines, result.getOutputLines("err"), result.getOutput("err")); + assertLinesMatch(expectedOutLines, result.getOutputLines("out")); + assertLinesMatch(expectedErrLines, result.getOutputLines("err")); var jupiterVersion = Helper.version("junit-jupiter-engine"); var vintageVersion = Helper.version("junit-vintage-engine"); From 3184a6e350590aa23142cb31d919bd68c257cad4 Mon Sep 17 00:00:00 2001 From: Andrei Rybak Date: Sun, 6 Aug 2023 19:27:17 +0200 Subject: [PATCH 016/142] Unify messages about exit codes in StandaloneTests Some tests in StandaloneTests provide concatenation of standard output and standard error as a message for the assertion about exit code, while other tests provide only standard output. Some use method de.sormuras.bartholdy.Result#getOutput while others use method de.sormuras.bartholdy.Result#getOutputLines. Unify these approaches by replacing the messages with a supplier that gives a) a human-readable message about exit codes, and b) both standard output and standard error. --- .../support/tests/StandaloneTests.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java index de76e04ef91b..b7d8057ffed9 100644 --- a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java +++ b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java @@ -69,7 +69,7 @@ void listAllObservableEngines() { .addArguments("engines", "--disable-ansi-colors", "--disable-banner").build() // .run(false); - assertEquals(0, result.getExitCode(), String.join("\n", result.getOutputLines("out"))); + assertEquals(0, result.getExitCode(), () -> getExitCodeMessage(result)); var jupiterVersion = Helper.version("junit-jupiter-engine"); var suiteVersion = Helper.version("junit-platform-suite-engine"); @@ -98,7 +98,7 @@ void compile() throws Exception { .addArguments(workspace.resolve("src/standalone/VintageIntegration.java")).build() // .run(); - assertEquals(0, result.getExitCode(), result.getOutput("out") + result.getOutput("err")); + assertEquals(0, result.getExitCode(), () -> getExitCodeMessage(result)); assertTrue(result.getOutput("out").isEmpty()); assertTrue(result.getOutput("err").isEmpty()); @@ -327,7 +327,7 @@ private static Result discover(String... args) { .build() // .run(false); - assertEquals(0, result.getExitCode(), String.join("\n", result.getOutputLines("out"))); + assertEquals(0, result.getExitCode(), () -> getExitCodeMessage(result)); return result; } @@ -349,7 +349,7 @@ void execute() throws IOException { .addArguments("--classpath", "bin").build() // .run(false); - assertEquals(1, result.getExitCode(), String.join("\n", result.getOutputLines("out"))); + assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); var workspace = Request.WORKSPACE.resolve("standalone"); var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); @@ -384,7 +384,7 @@ void executeOnJava8() throws IOException { .addArguments("--classpath", "bin").build() // .run(false); - assertEquals(1, result.getExitCode(), String.join("\n", result.getOutputLines("out"))); + assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); var workspace = Request.WORKSPACE.resolve("standalone"); var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); @@ -420,7 +420,7 @@ void executeOnJava8SelectPackage() throws IOException { .addArguments("--classpath", "bin").build() // .run(false); - assertEquals(1, result.getExitCode(), String.join("\n", result.getOutputLines("out"))); + assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); var workspace = Request.WORKSPACE.resolve("standalone"); var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); @@ -461,6 +461,11 @@ void executeWithJarredTestClasses() { .build() // .run(false); - assertEquals(1, result.getExitCode(), String.join("\n", result.getOutputLines("out"))); + assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); + } + + private static String getExitCodeMessage(Result result) { + return "Exit codes don't match. Stdout:\n" + result.getOutput("out") + // + "\n\nStderr:\n" + result.getOutput("err") + "\n"; } } From 977c85fc31ad6825b4c68f6c6c972a93356ffe74 Mon Sep 17 00:00:00 2001 From: Andrei Rybak Date: Sun, 6 Aug 2023 23:47:02 +0200 Subject: [PATCH 017/142] Run StandaloneTests for Java 8 under Java 8 Problem ------- Tests that claim by their name to run on Java 8 don't actually run on Java 8. This can be clear from the output for tests that add option `--show-version` to the arguments and _don't_ fail -- they all print the version for the current JDK. The tool `java` of JDK 8 does _not_ have the option `--show-version`. The actual option that exists in JDK 8 has fewer hyphens, as per documentation of Java 8 [1]: -showversion Displays version information and continues execution of the application. This option is equivalent to the `-version` option except that the latter instructs the JVM to exit after displaying version information. And when I actually run Java 8 binary with the incorrect option `--show-version` used by the affected tests, I get: $ /usr/lib/jvm/java-8-openjdk-amd64/bin/java --show-version Unrecognized option: --show-version Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. The option `--show-version` was only added in Java 9 [2]. Explanation ----------- In actuality, the tests are being run on whatever the current JDK is. These tests create an instance of class `de.sormuras.bartholdy.tool.Java`, which importantly has the following method: @Override public Path getHome() { return Bartholdy.currentJdkHome(); } When the `bartholdy` library creates the process, class `AbstractTool` does the following: protected Path createPathToProgram() { return getHome().resolve("bin").resolve(getProgram()); } The string `"java"` returned from method `getProgram` of class `Java` gets resolved against `Bartholdy.currentJdkHome()`. As far as I can tell, the library doesn't promise to look up the `java` binary in the `JAVA_HOME` supplied in the environment. In fact, just before consuming library user's environment, method `run()` of class `de.sormuras.bartholdy.tool.AbstractTool` puts the current JDK as `JAVA_HOME` into the environment to correspond to the behavior of class `de.sormuras.bartholdy.tool.Java` described above: builder.environment().put("JAVA_HOME", Bartholdy.currentJdkHome().toString()); The issue has been present since commit [3] where these tests were introduced. Fix --- Fix affected tests to run them under actual Java 8 by overriding method `de.sormuras.bartholdy.tool.Java#getHome`. Replace erroneous option `--show-version` with `-showversion`. To make tests executeOnJava8() and executeOnJava8SelectPackage() see the class files, update test compile() to use option `--release 8`. Because compiling to release 8 is deprecated, add a linter option to disable the warning to make compile() pass. Because option `-showversion` of Java 8 behaves slightly differently to option `--show-version` of later versions of Java, prepare two new files for expected stdout and stderr: expected-out-java8.txt and expected-err-java8.txt, which are similar to existing files expected-out.txt and expected-err.txt, but have different layout of fastforward lines "JAVA VERSION" and "TREE". Footnotes --------- [1] "Java Platform, Standard Edition Tools Reference", "java" https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html [2] https://docs.oracle.com/javase/9/tools/java.htm > `--show-version` or `-showversion` > > Displays version information and continues execution of the application. > This option is equivalent to the `-version` option except that the latter > instructs the JVM to exit after displaying version information. [3] c62cd6ab11 (Fix package path computation in `ClasspathScanner`, 2021-05-12) from https://github.com/junit-team/junit5/pull/2613 --- .../standalone/expected-err-java8.txt | 21 ++++++++++ .../standalone/expected-out-java8.txt | 18 ++++++++ .../support/tests/StandaloneTests.java | 42 ++++++++++++++----- 3 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 platform-tooling-support-tests/projects/standalone/expected-err-java8.txt create mode 100644 platform-tooling-support-tests/projects/standalone/expected-out-java8.txt diff --git a/platform-tooling-support-tests/projects/standalone/expected-err-java8.txt b/platform-tooling-support-tests/projects/standalone/expected-err-java8.txt new file mode 100644 index 000000000000..70a3db689cc9 --- /dev/null +++ b/platform-tooling-support-tests/projects/standalone/expected-err-java8.txt @@ -0,0 +1,21 @@ +>> JAVA VERSION >> +.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load +.+ Loaded LauncherInterceptor instances: .. +.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load +.+ Loaded LauncherSessionListener instances: .. +.+ org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry loadTestEngines +.+ Discovered TestEngines: +- junit-jupiter .+ +- junit-vintage .+ +- junit-platform-suite .+ +.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load +.+ Loaded PostDiscoveryFilter instances: .. +.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load +.+ Loaded LauncherDiscoveryListener instances: .. +.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load +.+ Loaded TestExecutionListener instances: .+ +.+ org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry loadTestEngines +.+ Discovered TestEngines: +- junit-jupiter .+ +- junit-vintage .+ +- junit-platform-suite .+ diff --git a/platform-tooling-support-tests/projects/standalone/expected-out-java8.txt b/platform-tooling-support-tests/projects/standalone/expected-out-java8.txt new file mode 100644 index 000000000000..0a1cc1ecfba8 --- /dev/null +++ b/platform-tooling-support-tests/projects/standalone/expected-out-java8.txt @@ -0,0 +1,18 @@ +>> TREE >> +Failures (2): +>> STACKTRACE >> + +Test run finished after \d+ ms +[ 11 containers found ] +[ 0 containers skipped ] +[ 11 containers started ] +[ 0 containers aborted ] +[ 11 containers successful ] +[ 0 containers failed ] +[ 10 tests found ] +[ 2 tests skipped ] +[ 8 tests started ] +[ 1 tests aborted ] +[ 5 tests successful ] +[ 2 tests failed ] + diff --git a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java index b7d8057ffed9..2bf5dc885a0c 100644 --- a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java +++ b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java @@ -89,6 +89,8 @@ void compile() throws Exception { var result = Request.builder() // .setTool(new Javac()) // .setProject("standalone") // + .addArguments("-Xlint:-options") // + .addArguments("--release", "8") // .addArguments("-proc:none") // .addArguments("-d", workspace.resolve("bin")) // .addArguments("--class-path", MavenRepo.jar("junit-platform-console-standalone")) // @@ -368,11 +370,12 @@ void execute() throws IOException { @Test @Order(4) void executeOnJava8() throws IOException { + Java java8 = getJava8(); var result = Request.builder() // - .setTool(new Java()) // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // + .setTool(java8) // + .setJavaHome(java8.getHome()) // .setProject("standalone") // - .addArguments("--show-version") // + .addArguments("-showversion") // .addArguments("-enableassertions") // .addArguments("-Djava.util.logging.config.file=logging.properties") // .addArguments("-Djunit.platform.launcher.interceptors.enabled=true") // @@ -387,8 +390,8 @@ void executeOnJava8() throws IOException { assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); var workspace = Request.WORKSPACE.resolve("standalone"); - var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); - var expectedErrLines = Files.readAllLines(workspace.resolve("expected-err.txt")); + var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out-java8.txt")); + var expectedErrLines = Files.readAllLines(workspace.resolve("expected-err-java8.txt")); assertLinesMatch(expectedOutLines, result.getOutputLines("out")); assertLinesMatch(expectedErrLines, result.getOutputLines("err")); @@ -404,11 +407,12 @@ void executeOnJava8() throws IOException { @Order(5) // https://github.com/junit-team/junit5/issues/2600 void executeOnJava8SelectPackage() throws IOException { + Java java8 = getJava8(); var result = Request.builder() // - .setTool(new Java()) // - .setJavaHome(Helper.getJavaHome("8").orElseThrow(TestAbortedException::new)) // + .setTool(java8) // + .setJavaHome(java8.getHome()) // .setProject("standalone") // - .addArguments("--show-version") // + .addArguments("-showversion") // .addArguments("-enableassertions") // .addArguments("-Djava.util.logging.config.file=logging.properties") // .addArguments("-Djunit.platform.launcher.interceptors.enabled=true") // @@ -423,8 +427,8 @@ void executeOnJava8SelectPackage() throws IOException { assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); var workspace = Request.WORKSPACE.resolve("standalone"); - var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); - var expectedErrLines = Files.readAllLines(workspace.resolve("expected-err.txt")); + var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out-java8.txt")); + var expectedErrLines = Files.readAllLines(workspace.resolve("expected-err-java8.txt")); assertLinesMatch(expectedOutLines, result.getOutputLines("out")); assertLinesMatch(expectedErrLines, result.getOutputLines("err")); @@ -468,4 +472,22 @@ private static String getExitCodeMessage(Result result) { return "Exit codes don't match. Stdout:\n" + result.getOutput("out") + // "\n\nStderr:\n" + result.getOutput("err") + "\n"; } + + /** + * Special override of class {@link Java} to resolve against a different {@code JAVA_HOME}. + */ + private static Java getJava8() { + Path java8Home = Helper.getJavaHome("8").orElseThrow(TestAbortedException::new); + return new Java() { + @Override + public Path getHome() { + return java8Home; + } + + @Override + public String getVersion() { + return "8"; + } + }; + } } From e802db4643085cd1c609ac84aa3e635f98719d3f Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 10 Sep 2023 12:37:53 +0200 Subject: [PATCH 018/142] Use same expected files for all JDK versions --- .../standalone/expected-err-java8.txt | 21 ------------------- .../standalone/expected-out-java8.txt | 18 ---------------- .../support/tests/StandaloneTests.java | 16 ++++++++++---- 3 files changed, 12 insertions(+), 43 deletions(-) delete mode 100644 platform-tooling-support-tests/projects/standalone/expected-err-java8.txt delete mode 100644 platform-tooling-support-tests/projects/standalone/expected-out-java8.txt diff --git a/platform-tooling-support-tests/projects/standalone/expected-err-java8.txt b/platform-tooling-support-tests/projects/standalone/expected-err-java8.txt deleted file mode 100644 index 70a3db689cc9..000000000000 --- a/platform-tooling-support-tests/projects/standalone/expected-err-java8.txt +++ /dev/null @@ -1,21 +0,0 @@ ->> JAVA VERSION >> -.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load -.+ Loaded LauncherInterceptor instances: .. -.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load -.+ Loaded LauncherSessionListener instances: .. -.+ org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry loadTestEngines -.+ Discovered TestEngines: -- junit-jupiter .+ -- junit-vintage .+ -- junit-platform-suite .+ -.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load -.+ Loaded PostDiscoveryFilter instances: .. -.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load -.+ Loaded LauncherDiscoveryListener instances: .. -.+ org.junit.platform.launcher.core.ServiceLoaderRegistry load -.+ Loaded TestExecutionListener instances: .+ -.+ org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry loadTestEngines -.+ Discovered TestEngines: -- junit-jupiter .+ -- junit-vintage .+ -- junit-platform-suite .+ diff --git a/platform-tooling-support-tests/projects/standalone/expected-out-java8.txt b/platform-tooling-support-tests/projects/standalone/expected-out-java8.txt deleted file mode 100644 index 0a1cc1ecfba8..000000000000 --- a/platform-tooling-support-tests/projects/standalone/expected-out-java8.txt +++ /dev/null @@ -1,18 +0,0 @@ ->> TREE >> -Failures (2): ->> STACKTRACE >> - -Test run finished after \d+ ms -[ 11 containers found ] -[ 0 containers skipped ] -[ 11 containers started ] -[ 0 containers aborted ] -[ 11 containers successful ] -[ 0 containers failed ] -[ 10 tests found ] -[ 2 tests skipped ] -[ 8 tests started ] -[ 1 tests aborted ] -[ 5 tests successful ] -[ 2 tests failed ] - diff --git a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java index 2bf5dc885a0c..a80071de8d41 100644 --- a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java +++ b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/StandaloneTests.java @@ -21,6 +21,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.List; import de.sormuras.bartholdy.Result; import de.sormuras.bartholdy.jdk.Jar; @@ -390,8 +391,8 @@ void executeOnJava8() throws IOException { assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); var workspace = Request.WORKSPACE.resolve("standalone"); - var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out-java8.txt")); - var expectedErrLines = Files.readAllLines(workspace.resolve("expected-err-java8.txt")); + var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); + var expectedErrLines = getExpectedErrLinesOnJava8(workspace); assertLinesMatch(expectedOutLines, result.getOutputLines("out")); assertLinesMatch(expectedErrLines, result.getOutputLines("err")); @@ -427,8 +428,8 @@ void executeOnJava8SelectPackage() throws IOException { assertEquals(1, result.getExitCode(), () -> getExitCodeMessage(result)); var workspace = Request.WORKSPACE.resolve("standalone"); - var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out-java8.txt")); - var expectedErrLines = Files.readAllLines(workspace.resolve("expected-err-java8.txt")); + var expectedOutLines = Files.readAllLines(workspace.resolve("expected-out.txt")); + var expectedErrLines = getExpectedErrLinesOnJava8(workspace); assertLinesMatch(expectedOutLines, result.getOutputLines("out")); assertLinesMatch(expectedErrLines, result.getOutputLines("err")); @@ -440,6 +441,13 @@ void executeOnJava8SelectPackage() throws IOException { + " (group ID: org.junit.vintage, artifact ID: junit-vintage-engine, version: " + vintageVersion)); } + private static List getExpectedErrLinesOnJava8(Path workspace) throws IOException { + var expectedErrLines = new ArrayList(); + expectedErrLines.add(">> JAVA VERSION >>"); + expectedErrLines.addAll(Files.readAllLines(workspace.resolve("expected-err.txt"))); + return expectedErrLines; + } + @Test @Order(6) @Disabled("https://github.com/junit-team/junit5/issues/1724") From d22b553e641c7c4eac0577d9b39a2d19e1c8c632 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:19:57 +0000 Subject: [PATCH 019/142] Bump github/combine-prs from 3.1.1 to 3.1.2 Bumps [github/combine-prs](https://github.com/github/combine-prs) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/github/combine-prs/releases) - [Commits](https://github.com/github/combine-prs/compare/v3.1.1...v3.1.2) --- updated-dependencies: - dependency-name: github/combine-prs dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/combine-prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml index 826472911980..3830dd033f27 100644 --- a/.github/workflows/combine-prs.yml +++ b/.github/workflows/combine-prs.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - name: combine-prs - uses: github/combine-prs@v3.1.1 + uses: github/combine-prs@v3.1.2 with: github_token: ${{ secrets.GH_TOKEN }} From 75959776190c1d85fac715a2ccd2612f17b5f631 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:20:11 +0000 Subject: [PATCH 020/142] Bump jmh from 1.36 to 1.37 Bumps `jmh` from 1.36 to 1.37. Updates `org.openjdk.jmh:jmh-core` from 1.36 to 1.37 - [Commits](https://github.com/openjdk/jmh/compare/1.36...1.37) Updates `org.openjdk.jmh:jmh-generator-annprocess` from 1.36 to 1.37 - [Commits](https://github.com/openjdk/jmh/compare/1.36...1.37) --- updated-dependencies: - dependency-name: org.openjdk.jmh:jmh-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.openjdk.jmh:jmh-generator-annprocess dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3ab2376f7982..8f8790213293 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ bnd = "6.4.0" checkstyle = "10.12.3" gradleVersionsPlugin = "0.47.0" jacoco = "0.8.7" -jmh = "1.36" +jmh = "1.37" junit4 = "4.13.2" junit4Osgi = "4.13.2_1" junit4Min = "4.12" From 04310d86de72f2484085e9ff6c3e27f7465d1731 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:20:22 +0000 Subject: [PATCH 021/142] Bump org.apache.maven:apache-maven from 3.9.3 to 3.9.4 Bumps [org.apache.maven:apache-maven](https://github.com/apache/maven) from 3.9.3 to 3.9.4. - [Release notes](https://github.com/apache/maven/releases) - [Commits](https://github.com/apache/maven/compare/maven-3.9.3...maven-3.9.4) --- updated-dependencies: - dependency-name: org.apache.maven:apache-maven dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8f8790213293..a1b478f3c4e3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,7 +50,7 @@ junit4 = { module = "junit:junit", version = { require = "[4.12,)", prefer = "4. kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.7.2" } log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4j" } -maven = { module = "org.apache.maven:apache-maven", version = "3.9.3" } +maven = { module = "org.apache.maven:apache-maven", version = "3.9.4" } mavenSurefirePlugin = { module = "org.apache.maven.plugins:maven-surefire-plugin", version.ref = "surefire" } memoryfilesystem = { module = "com.github.marschall:memoryfilesystem", version = "2.6.1" } mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.4.0" } From a01f683595943ff4c73dccd47f085d5914d2bcc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:20:33 +0000 Subject: [PATCH 022/142] Bump com.gradle:gradle-enterprise-gradle-plugin from 3.14 to 3.14.1 Bumps com.gradle:gradle-enterprise-gradle-plugin from 3.14 to 3.14.1. --- updated-dependencies: - dependency-name: com.gradle:gradle-enterprise-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a1b478f3c4e3..601a3534e62d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,7 +33,7 @@ classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.161" } commons-io = { module = "commons-io:commons-io", version = "2.13.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.1" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.6.0" } -gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.14" } +gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.14.1" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.20.0" } From 2a173cae5aba1bd371559ef226bb8208ae647e84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:20:43 +0000 Subject: [PATCH 023/142] Bump org.jetbrains.kotlinx:kotlinx-coroutines-core from 1.7.2 to 1.7.3 Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-core](https://github.com/Kotlin/kotlinx.coroutines) from 1.7.2 to 1.7.3. - [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases) - [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md) - [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.7.2...1.7.3) --- updated-dependencies: - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 601a3534e62d..5beb9fc57e0c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -47,7 +47,7 @@ jmh-core = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" } jmh-generator-annprocess = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.ref = "jmh" } joox = { module = "org.jooq:joox", version = "2.0.0" } junit4 = { module = "junit:junit", version = { require = "[4.12,)", prefer = "4.13.2" } } -kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.7.2" } +kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.7.3" } log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4j" } maven = { module = "org.apache.maven:apache-maven", version = "3.9.4" } From e345e98e65a6ace7387e574cba5b19ea57d3c5a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 05:09:02 +0000 Subject: [PATCH 024/142] Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/cross-version.yml | 2 +- .github/workflows/gradle-wrapper-validation.yml | 2 +- .github/workflows/main.yml | 10 +++++----- .github/workflows/reproducible-build.yml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 63b648c7b424..417681a63c55 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,7 +30,7 @@ jobs: - javascript steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: diff --git a/.github/workflows/cross-version.yml b/.github/workflows/cross-version.yml index 8480a68a49c7..8c96b261d081 100644 --- a/.github/workflows/cross-version.yml +++ b/.github/workflows/cross-version.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Set up Test JDK diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index de5d0346a9f6..f0737751f838 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Validate Gradle wrapper diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 676ec1a2f87a..afde23101ed5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Install Graphviz @@ -49,7 +49,7 @@ jobs: runs-on: windows-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Build @@ -59,7 +59,7 @@ jobs: runs-on: macos-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Build @@ -72,7 +72,7 @@ jobs: if: github.event_name == 'push' && github.repository == 'junit-team/junit5' && (startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main') steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Publish @@ -93,7 +93,7 @@ jobs: if: github.event_name == 'push' && github.repository == 'junit-team/junit5' && github.ref == 'refs/heads/main' steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Install Graphviz diff --git a/.github/workflows/reproducible-build.yml b/.github/workflows/reproducible-build.yml index a32a51ac0002..724405a4c7d8 100644 --- a/.github/workflows/reproducible-build.yml +++ b/.github/workflows/reproducible-build.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 1 - name: Restore Gradle cache and display toolchains From 179cd2dc4e376e645c8b606caf16f6131cd142ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 05:50:58 +0000 Subject: [PATCH 025/142] Bump org.mockito:mockito-junit-jupiter from 5.4.0 to 5.5.0 Bumps [org.mockito:mockito-junit-jupiter](https://github.com/mockito/mockito) from 5.4.0 to 5.5.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.4.0...v5.5.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5beb9fc57e0c..7c1bf97e58a0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -53,7 +53,7 @@ log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4 maven = { module = "org.apache.maven:apache-maven", version = "3.9.4" } mavenSurefirePlugin = { module = "org.apache.maven.plugins:maven-surefire-plugin", version.ref = "surefire" } memoryfilesystem = { module = "com.github.marschall:memoryfilesystem", version = "2.6.1" } -mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.4.0" } +mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.5.0" } opentest4j = { module = "org.opentest4j:opentest4j", version.ref = "opentest4j" } openTestReporting-events = { module = "org.opentest4j.reporting:open-test-reporting-events", version.ref = "openTestReporting" } openTestReporting-tooling = { module = "org.opentest4j.reporting:open-test-reporting-tooling", version.ref = "openTestReporting" } From 7b602b2a33a87d5e875727e26afb7c7712a73274 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 05:51:01 +0000 Subject: [PATCH 026/142] Bump org.slf4j:slf4j-jdk14 from 2.0.7 to 2.0.9 Bumps org.slf4j:slf4j-jdk14 from 2.0.7 to 2.0.9. --- updated-dependencies: - dependency-name: org.slf4j:slf4j-jdk14 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c1bf97e58a0..5fce7adade7a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -58,7 +58,7 @@ opentest4j = { module = "org.opentest4j:opentest4j", version.ref = "opentest4j" openTestReporting-events = { module = "org.opentest4j.reporting:open-test-reporting-events", version.ref = "openTestReporting" } openTestReporting-tooling = { module = "org.opentest4j.reporting:open-test-reporting-tooling", version.ref = "openTestReporting" } picocli = { module = "info.picocli:picocli", version = "4.7.5" } -slf4j-julBinding = { module = "org.slf4j:slf4j-jdk14", version = "2.0.7" } +slf4j-julBinding = { module = "org.slf4j:slf4j-jdk14", version = "2.0.9" } spock1 = { module = "org.spockframework:spock-core", version = "1.3-groovy-2.5" } univocity-parsers = { module = "com.univocity:univocity-parsers", version = "2.9.1" } xmlunit-assertj = { module = "org.xmlunit:xmlunit-assertj3", version.ref = "xmlunit" } From 08c51d7c6882841db8540aab40a89d057ab7812b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 05:51:05 +0000 Subject: [PATCH 027/142] Bump io.github.classgraph:classgraph from 4.8.161 to 4.8.162 Bumps [io.github.classgraph:classgraph](https://github.com/classgraph/classgraph) from 4.8.161 to 4.8.162. - [Release notes](https://github.com/classgraph/classgraph/releases) - [Commits](https://github.com/classgraph/classgraph/compare/classgraph-4.8.161...classgraph-4.8.162) --- updated-dependencies: - dependency-name: io.github.classgraph:classgraph dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5fce7adade7a..d9914629aa30 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } -classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.161" } +classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.162" } commons-io = { module = "commons-io:commons-io", version = "2.13.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.1" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.6.0" } From d2083ef741d02901d0b01e20db794aaef150aa88 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 05:51:10 +0000 Subject: [PATCH 028/142] Bump ant from 1.10.13 to 1.10.14 Bumps `ant` from 1.10.13 to 1.10.14. Updates `org.apache.ant:ant` from 1.10.13 to 1.10.14 Updates `org.apache.ant:ant-junit` from 1.10.13 to 1.10.14 Updates `org.apache.ant:ant-junitlauncher` from 1.10.13 to 1.10.14 --- updated-dependencies: - dependency-name: org.apache.ant:ant dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.ant:ant-junit dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.ant:ant-junitlauncher dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d9914629aa30..834b9d308d4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -ant = "1.10.13" +ant = "1.10.14" apiguardian = "1.1.2" asciidoctor-pdf = "1.5.3" asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gradle.kts can be removed when upgrading From 7082d3d9169cf06c559bd86f723f95c9a597a704 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 05:51:12 +0000 Subject: [PATCH 029/142] Bump org.gradle.toolchains:foojay-resolver from 0.6.0 to 0.7.0 Bumps org.gradle.toolchains:foojay-resolver from 0.6.0 to 0.7.0. --- updated-dependencies: - dependency-name: org.gradle.toolchains:foojay-resolver dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 834b9d308d4a..c7ac9a7c9292 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,7 @@ checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checks classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.162" } commons-io = { module = "commons-io:commons-io", version = "2.13.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.1" } -gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.6.0" } +gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.14.1" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } From 3fca251a1bc628b0b285027c0856b91b852c440c Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 15 Sep 2023 10:17:56 +0200 Subject: [PATCH 030/142] =?UTF-8?q?Document=20that=20@=E2=81=A0Disabled=20?= =?UTF-8?q?&=20conditional=20annotations=20are=20not=20inherited?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #3462 --- .../asciidoc/user-guide/writing-tests.adoc | 19 ++++++++++++++++++- .../java/org/junit/jupiter/api/Disabled.java | 4 ++++ .../api/condition/DisabledForJreRange.java | 4 ++++ .../jupiter/api/condition/DisabledIf.java | 4 ++++ .../DisabledIfEnvironmentVariable.java | 4 ++++ .../DisabledIfEnvironmentVariables.java | 4 ++++ .../condition/DisabledIfSystemProperties.java | 4 ++++ .../condition/DisabledIfSystemProperty.java | 4 ++++ .../api/condition/DisabledInNativeImage.java | 4 ++++ .../jupiter/api/condition/DisabledOnJre.java | 4 ++++ .../jupiter/api/condition/DisabledOnOs.java | 4 ++++ .../api/condition/EnabledForJreRange.java | 4 ++++ .../jupiter/api/condition/EnabledIf.java | 4 ++++ .../EnabledIfEnvironmentVariable.java | 4 ++++ .../EnabledIfEnvironmentVariables.java | 4 ++++ .../condition/EnabledIfSystemProperties.java | 4 ++++ .../condition/EnabledIfSystemProperty.java | 4 ++++ .../api/condition/EnabledInNativeImage.java | 4 ++++ .../jupiter/api/condition/EnabledOnJre.java | 4 ++++ .../jupiter/api/condition/EnabledOnOs.java | 4 ++++ 20 files changed, 94 insertions(+), 1 deletion(-) diff --git a/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc b/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc index 0a0862b6f2b8..4f8d59925fbf 100644 --- a/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc +++ b/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc @@ -371,12 +371,22 @@ And here's a test class that contains a `@Disabled` test method. include::{testDir}/example/DisabledTestsDemo.java[tags=user_guide] ---- -NOTE: `@Disabled` may be declared without providing a _reason_; however, the JUnit team +[TIP] +==== +`@Disabled` may be declared without providing a _reason_; however, the JUnit team recommends that developers provide a short explanation for why a test class or test method has been disabled. Consequently, the above examples both show the use of a reason -- for example, `@Disabled("Disabled until bug #42 has been resolved")`. Some development teams even require the presence of issue tracking numbers in the _reason_ for automated traceability, etc. +==== + +[NOTE] +==== +`@Disabled` is not `@Inherited`. Consequently, if you wish to disable a class whose +superclass is `@Disabled`, you must redeclare `@Disabled` on the subclass. +==== + [[writing-tests-conditional-execution]] === Conditional Test Execution @@ -406,6 +416,13 @@ example, the `@TestOnMac` annotation in the combine `@Test` and `@EnabledOnOs` in a single, reusable annotation. ==== +[NOTE] +==== +_Conditional_ annotations in JUnit Jupiter are not `@Inherited`. Consequently, if you wish +to apply the same semantics to subclasses, each conditional annotation must be redeclared +on each subclass. +==== + [WARNING] ==== Unless otherwise stated, each of the _conditional_ annotations listed in the following diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Disabled.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Disabled.java index 9a7717053491..6394a84634c3 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Disabled.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/Disabled.java @@ -30,6 +30,10 @@ *

When applied at the class level, all test methods within that class * are automatically disabled as well. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

When applied at the method level, the presence of this annotation does not * prevent the test class from being instantiated. Rather, it prevents the * execution of the test method and method-level lifecycle callbacks such as diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java index a3b0762e0de5..47d5af673cd2 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java @@ -29,6 +29,10 @@ *

When applied at the class level, all test methods within that class will * be disabled on the same specified JRE versions. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java index 06bdd569048a..88e3f8e329fd 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java @@ -29,6 +29,10 @@ *

When applied at the class level, all test methods within that class will * be disabled on the same condition. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.java index 0cc90eec72a4..ea4f0a147a67 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariable.java @@ -31,6 +31,10 @@ *

When declared at the class level, the result will apply to all test methods * within that class as well. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariables.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariables.java index deef2a4a8fa0..6b473d684cff 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariables.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfEnvironmentVariables.java @@ -28,6 +28,10 @@ * is completely optional since {@code @DisabledIfEnvironmentVariable} is a {@linkplain * java.lang.annotation.Repeatable repeatable} annotation. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * * @since 5.6 * @see DisabledIfEnvironmentVariable * @see java.lang.annotation.Repeatable diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperties.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperties.java index ff6877bf1a06..eb351cb2ea14 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperties.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperties.java @@ -28,6 +28,10 @@ * is completely optional since {@code @DisabledIfSystemProperty} is a {@linkplain * java.lang.annotation.Repeatable repeatable} annotation. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * * @since 5.6 * @see DisabledIfSystemProperty * @see java.lang.annotation.Repeatable diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperty.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperty.java index ac7d0937d848..ce767e6afa95 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperty.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIfSystemProperty.java @@ -31,6 +31,10 @@ *

When declared at the class level, the result will apply to all test methods * within that class as well. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java index a96399e799be..d996b71705d8 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java @@ -28,6 +28,10 @@ *

When applied at the class level, all test methods within that class will * be disabled within a native image. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java index 2aa7f012c947..e707c0f74a99 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java @@ -29,6 +29,10 @@ *

When applied at the class level, all test methods within that class * will be disabled on the same specified JRE versions. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOs.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOs.java index f067c2290083..3e843a545387 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOs.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnOs.java @@ -34,6 +34,10 @@ * will be disabled on the same specified operating systems, architectures, or * the specified combinations of both. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java index b1efb7c88e0d..ed1a74b06e09 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java @@ -29,6 +29,10 @@ *

When applied at the class level, all test methods within that class will * be enabled on the same specified JRE versions. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java index 5bd4b3df30e7..2087c1ca1de6 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java @@ -29,6 +29,10 @@ *

When applied at the class level, all test methods within that class will * be enabled on the same condition. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.java index 44cf3bf5940f..11c48fdf369a 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariable.java @@ -31,6 +31,10 @@ *

When declared at the class level, the result will apply to all test methods * within that class as well. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariables.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariables.java index 3589ed58b217..928c8582dd80 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariables.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfEnvironmentVariables.java @@ -28,6 +28,10 @@ * is completely optional since {@code @EnabledIfEnvironmentVariable} is a {@linkplain * java.lang.annotation.Repeatable repeatable} annotation. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * * @since 5.6 * @see EnabledIfEnvironmentVariable * @see java.lang.annotation.Repeatable diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperties.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperties.java index f33bdfae4790..2a3a32c6f6c5 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperties.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperties.java @@ -28,6 +28,10 @@ * is completely optional since {@code @EnabledIfSystemProperty} is a {@linkplain * java.lang.annotation.Repeatable repeatable} annotation. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * * @since 5.6 * @see EnabledIfSystemProperty * @see java.lang.annotation.Repeatable diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperty.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperty.java index 26cbcc10743a..99587b7085d5 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperty.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIfSystemProperty.java @@ -31,6 +31,10 @@ *

When declared at the class level, the result will apply to all test methods * within that class as well. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledInNativeImage.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledInNativeImage.java index 33641509e7a0..98504f74f653 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledInNativeImage.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledInNativeImage.java @@ -28,6 +28,10 @@ *

When applied at the class level, all test methods within that class will * be enabled within a native image. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java index ab6e18a193e4..9b454a5744ba 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java @@ -29,6 +29,10 @@ *

When applied at the class level, all test methods within that class * will be enabled on the same specified JRE versions. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOs.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOs.java index de284cd68654..838579e4251a 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOs.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnOs.java @@ -34,6 +34,10 @@ * will be enabled on the same specified operating systems, architectures, or * the specified combinations of both. * + *

This annotation is not {@link java.lang.annotation.Inherited @Inherited}. + * Consequently, if you wish to apply the same semantics to a subclass, this + * annotation must be redeclared on the subclass. + * *

If a test method is disabled via this annotation, that does not prevent * the test class from being instantiated. Rather, it prevents the execution of * the test method and method-level lifecycle callbacks such as {@code @BeforeEach} From b58d87192914551db1836458b97b06d2d506e581 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 16 Sep 2023 14:54:24 +0200 Subject: [PATCH 031/142] Fix implementation of RandomNumberExtension in the User Guide With this commit, the RandomNumberExtension example in the User Guide now properly supports non-static field injection. See #3437 Closes #3433 --- .../release-notes/release-notes-5.10.1.adoc | 4 +++- .../docs/asciidoc/user-guide/extensions.adoc | 22 ++++++++++++++----- .../example/extensions/RandomNumberDemo.java | 2 +- .../extensions/RandomNumberExtension.java | 7 +++--- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc index f3186db2b66a..f79ffa8d72d0 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -31,7 +31,9 @@ JUnit repository on GitHub. ==== Bug Fixes -* ❓ +* The `RandomNumberExtension` example in the + <<../user-guide/index.adoc#extensions-RandomNumberExtension, User Guide>> has been + updated to properly support `Integer` types as well as non-static field injection. ==== Deprecations and Breaking Changes diff --git a/documentation/src/docs/asciidoc/user-guide/extensions.adoc b/documentation/src/docs/asciidoc/user-guide/extensions.adoc index 09ca2ec5e88b..e8a1512a5e40 100644 --- a/documentation/src/docs/asciidoc/user-guide/extensions.adoc +++ b/documentation/src/docs/asciidoc/user-guide/extensions.adoc @@ -99,7 +99,7 @@ public @interface DatabaseAndWebServerExtension { The above examples demonstrate how `@ExtendWith` can be applied at the class level or at the method level; however, for certain use cases it makes sense for an extension to be registered declaratively at the field or parameter level. Consider a -`RandomNumberExtension` that generates random numbers that can be injected into a field or +`RandomNumberExtension` which generates random numbers that can be injected into a field or via a parameter in a constructor, test method, or lifecycle method. If the extension provides a `@Random` annotation that is meta-annotated with `@ExtendWith(RandomNumberExtension.class)` (see listing below), the extension can be used @@ -118,17 +118,29 @@ include::{testDir}/example/extensions/RandomNumberDemo.java[tags=user_guide] [[extensions-RandomNumberExtension]] The following code listing provides an example of how one might choose to implement such a `RandomNumberExtension`. This implementation works for the use cases in -`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases – for -example, the random number generation support is limited to integers, it uses -`java.util.Random` instead of `java.security.SecureRandom`, etc. In any case, it is +`RandomNumberDemo`; however, it may not prove robust enough to cover all use cases -- for +example, the random number generation support is limited to integers; it uses +`java.util.Random` instead of `java.security.SecureRandom`; etc. In any case, it is important to note which extension APIs are implemented and for what reasons. Specifically, `RandomNumberExtension` implements the following extension APIs: - `BeforeAllCallback`: to support static field injection -- `TestInstancePostProcessor`: to support non-static field injection +- `BeforeEachCallback`: to support non-static field injection - `ParameterResolver`: to support constructor and method injection +[NOTE] +==== +Ideally, the `RandomNumberExtension` would implement `TestInstancePostProcessor` instead +of `BeforeEachCallback` in order to support non-static field injection immediately after +the test class has been instantiated. + +However, JUnit Jupiter currently does not allow a `TestInstancePostProcessor` to be +registered via `@ExtendWith` on a non-static field (see +link:{junit5-repo}/issues/3437[issue 3437]). In light of that, the `RandomNumberExtension` +implements `BeforeEachCallback` as an alternative approach. +==== + [source,java,indent=0] ---- include::{testDir}/example/extensions/RandomNumberExtension.java[tags=user_guide] diff --git a/documentation/src/test/java/example/extensions/RandomNumberDemo.java b/documentation/src/test/java/example/extensions/RandomNumberDemo.java index 8dd274bda73c..0589e1e19b29 100644 --- a/documentation/src/test/java/example/extensions/RandomNumberDemo.java +++ b/documentation/src/test/java/example/extensions/RandomNumberDemo.java @@ -27,7 +27,7 @@ class RandomNumberDemo { private int randomNumber1; RandomNumberDemo(@Random int randomNumber2) { - // Use randomNumber2 in constructor + // Use randomNumber2 in constructor. } @BeforeEach diff --git a/documentation/src/test/java/example/extensions/RandomNumberExtension.java b/documentation/src/test/java/example/extensions/RandomNumberExtension.java index b2a900dc5ea5..f550a57cd3d0 100644 --- a/documentation/src/test/java/example/extensions/RandomNumberExtension.java +++ b/documentation/src/test/java/example/extensions/RandomNumberExtension.java @@ -18,17 +18,17 @@ import java.util.function.Predicate; import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterResolver; -import org.junit.jupiter.api.extension.TestInstancePostProcessor; import org.junit.platform.commons.support.ModifierSupport; // end::user_guide[] // @formatter:off // tag::user_guide[] class RandomNumberExtension - implements BeforeAllCallback, TestInstancePostProcessor, ParameterResolver { + implements BeforeAllCallback, BeforeEachCallback, ParameterResolver { private final java.util.Random random = new java.util.Random(System.nanoTime()); @@ -47,8 +47,9 @@ public void beforeAll(ExtensionContext context) { * {@code @Random} and can be assigned an integer value. */ @Override - public void postProcessTestInstance(Object testInstance, ExtensionContext context) { + public void beforeEach(ExtensionContext context) { Class testClass = context.getRequiredTestClass(); + Object testInstance = context.getRequiredTestInstance(); injectFields(testClass, testInstance, ModifierSupport::isNotStatic); } From f72200613b931397e697587c7451431ae8c41797 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 16 Sep 2023 14:57:53 +0200 Subject: [PATCH 032/142] Polishing --- .../src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc index f79ffa8d72d0..1d98efa72b9c 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -49,7 +49,7 @@ JUnit repository on GitHub. ==== Bug Fixes -* Fix reporting of JUnit 3 test classes with `@Ignored` annotation +* Fixed reporting for JUnit 3 test classes that use JUnit 4's `@Ignored` annotation. ==== Deprecations and Breaking Changes From 70e33483530259edef1ab3c1ba12971ac3fc7db7 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 16 Sep 2023 15:03:39 +0200 Subject: [PATCH 033/142] Document additional enhancements in 5.10.1 --- .../src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc index 1d98efa72b9c..10d42587bbb9 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -41,7 +41,9 @@ JUnit repository on GitHub. ==== New Features and Improvements -* ❓ +* Improved Javadoc for `Assertions.assertTimeoutPreemptively` regarding thread interrupt. +* Documentation for `@Disabled` and conditional annotations now explicitly explains that + such annotations are not inherited by subclasses. [[release-notes-5.10.1-junit-vintage]] From e83dfb6a6e0948b949fc055ee716742d0f2aa856 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 05:46:53 +0000 Subject: [PATCH 034/142] Bump github/combine-prs from 3.1.2 to 4.0.0 Bumps [github/combine-prs](https://github.com/github/combine-prs) from 3.1.2 to 4.0.0. - [Release notes](https://github.com/github/combine-prs/releases) - [Commits](https://github.com/github/combine-prs/compare/v3.1.2...v4.0.0) --- updated-dependencies: - dependency-name: github/combine-prs dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/combine-prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml index 3830dd033f27..d0c826295265 100644 --- a/.github/workflows/combine-prs.yml +++ b/.github/workflows/combine-prs.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - name: combine-prs - uses: github/combine-prs@v3.1.2 + uses: github/combine-prs@v4.0.0 with: github_token: ${{ secrets.GH_TOKEN }} From 004ef07aa9190fbfcc0a6029029bbd3a79275fb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 05:55:51 +0000 Subject: [PATCH 035/142] Bump com.gradle:gradle-enterprise-gradle-plugin from 3.14.1 to 3.15 Bumps com.gradle:gradle-enterprise-gradle-plugin from 3.14.1 to 3.15. --- updated-dependencies: - dependency-name: com.gradle:gradle-enterprise-gradle-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c7ac9a7c9292..542c7d552ac9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,7 +33,7 @@ classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.162" } commons-io = { module = "commons-io:commons-io", version = "2.13.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.1" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } -gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.14.1" } +gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.20.0" } From c52ceed900389206d9b7df841944ab24da59b853 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 05:55:59 +0000 Subject: [PATCH 036/142] Bump com.gradle:gradle-enterprise-testing-annotations from 1.1 to 1.1.1 Bumps [com.gradle:gradle-enterprise-testing-annotations](https://github.com/gradle/gradle-enterprise-testing-annotations) from 1.1 to 1.1.1. - [Release notes](https://github.com/gradle/gradle-enterprise-testing-annotations/releases) - [Commits](https://github.com/gradle/gradle-enterprise-testing-annotations/compare/1.1...1.1.1) --- updated-dependencies: - dependency-name: com.gradle:gradle-enterprise-testing-annotations dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 542c7d552ac9..6b57e3e75dbd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -63,7 +63,7 @@ spock1 = { module = "org.spockframework:spock-core", version = "1.3-groovy-2.5" univocity-parsers = { module = "com.univocity:univocity-parsers", version = "2.9.1" } xmlunit-assertj = { module = "org.xmlunit:xmlunit-assertj3", version.ref = "xmlunit" } xmlunit-placeholders = { module = "org.xmlunit:xmlunit-placeholders", version.ref = "xmlunit" } -testingAnnotations = { module = "com.gradle:gradle-enterprise-testing-annotations", version = "1.1" } +testingAnnotations = { module = "com.gradle:gradle-enterprise-testing-annotations", version = "1.1.1" } [bundles] ant = ["ant", "ant-junit", "ant-junitlauncher"] From e8fcb95eb163ca888ae13965296db66ec55031b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 05:56:03 +0000 Subject: [PATCH 037/142] Bump com.diffplug.spotless:spotless-plugin-gradle from 6.20.0 to 6.21.0 Bumps [com.diffplug.spotless:spotless-plugin-gradle](https://github.com/diffplug/spotless) from 6.20.0 to 6.21.0. - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](https://github.com/diffplug/spotless/compare/gradle/6.20.0...gradle/6.21.0) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-plugin-gradle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6b57e3e75dbd..2e4bcb2104bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,7 +36,7 @@ gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", vers gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } -gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.20.0" } +gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.21.0" } gradle-versions = { module = "com.github.ben-manes:gradle-versions-plugin", version.ref = "gradleVersionsPlugin" } groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.13" } groovy2-bom = { module = "org.codehaus.groovy:groovy-bom", version = "2.5.21" } From f91db3af55570da3bcaacf5e74b7e14b91dba9f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 05:56:11 +0000 Subject: [PATCH 038/142] Bump gradleVersionsPlugin from 0.47.0 to 0.48.0 Bumps `gradleVersionsPlugin` from 0.47.0 to 0.48.0. Updates `com.github.ben-manes:gradle-versions-plugin` from 0.47.0 to 0.48.0 - [Release notes](https://github.com/ben-manes/gradle-versions-plugin/releases) - [Commits](https://github.com/ben-manes/gradle-versions-plugin/compare/v0.47.0...v0.48.0) Updates `com.github.ben-manes.versions` from 0.47.0 to 0.48.0 --- updated-dependencies: - dependency-name: com.github.ben-manes:gradle-versions-plugin dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.github.ben-manes.versions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2e4bcb2104bd..6b3a667d6466 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gra assertj = "3.24.2" bnd = "6.4.0" checkstyle = "10.12.3" -gradleVersionsPlugin = "0.47.0" +gradleVersionsPlugin = "0.48.0" jacoco = "0.8.7" jmh = "1.37" junit4 = "4.13.2" From 7cfae80e7ab0e1fc0ce95190e59d93c3f77bebd9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 05:56:12 +0000 Subject: [PATCH 039/142] Bump com.gradle:common-custom-user-data-gradle-plugin Bumps com.gradle:common-custom-user-data-gradle-plugin from 1.11.1 to 1.11.2. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6b3a667d6466..e052d68fd896 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.162" } commons-io = { module = "commons-io:commons-io", version = "2.13.0" } -gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.1" } +gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.2" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } From 849ce5ed327548a62ffd3cf813c19d28be1d3d0d Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 22 Sep 2023 12:54:55 +0200 Subject: [PATCH 040/142] Test 5.9.x behavior for null/"null" conversion support in parameterized tests 2 tests in this commit currently fail due to changes in 5.10 with the failure message: Failed to convert String "null" to type java.lang.Boolean This will be addressed in a subsequent commit to align with the expected behavior in 5.10.x. See #3472 --- .../ParameterizedTestIntegrationTests.java | 34 ++++++++++++ .../DefaultArgumentConverterTests.java | 53 +++++++++++++++++++ .../provider/CsvArgumentsProviderTests.java | 5 +- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java index 2f248bfdad42..78a5ed438582 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java @@ -111,6 +111,40 @@ */ class ParameterizedTestIntegrationTests { + @ParameterizedTest + @CsvSource(textBlock = """ + apple, True + banana, true + lemon, false + kumquat, null + """) + void sweetFruit(String fruit, Boolean sweet) { + switch (fruit) { + case "apple" -> assertThat(sweet).isTrue(); + case "banana" -> assertThat(sweet).isTrue(); + case "lemon" -> assertThat(sweet).isFalse(); + case "kumquat" -> assertThat(sweet).isFalse(); // "null" --> false + default -> fail("Unexpected fruit : " + fruit); + } + } + + @ParameterizedTest + @CsvSource(nullValues = "null", textBlock = """ + apple, True + banana, true + lemon, false + kumquat, null + """) + void sweetFruitWithNullableBoolean(String fruit, Boolean sweet) { + switch (fruit) { + case "apple" -> assertThat(sweet).isTrue(); + case "banana" -> assertThat(sweet).isTrue(); + case "lemon" -> assertThat(sweet).isFalse(); + case "kumquat" -> assertThat(sweet).isNull(); // null --> null + default -> fail("Unexpected fruit : " + fruit); + } + } + @ParameterizedTest @CsvSource(quoteCharacter = '"', textBlock = """ diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java index 90d8fb062792..d33645068d05 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java @@ -47,6 +47,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.junit.platform.commons.test.TestClassLoader; import org.junit.platform.commons.util.ReflectionUtils; @@ -61,11 +63,13 @@ class DefaultArgumentConverterTests { void isAwareOfNull() { assertConverts(null, Object.class, null); assertConverts(null, String.class, null); + assertConverts(null, Boolean.class, null); } @Test void isAwareOfWrapperTypesForPrimitiveTypes() { assertConverts(true, boolean.class, true); + assertConverts(false, boolean.class, false); assertConverts((byte) 1, byte.class, (byte) 1); assertConverts('o', char.class, 'o'); assertConverts((short) 1, short.class, (short) 1); @@ -91,6 +95,7 @@ void isAwareOfWideningConversions() { @Test void convertsStringsToPrimitiveTypes() { assertConverts("true", boolean.class, true); + assertConverts("false", boolean.class, false); assertConverts("o", char.class, 'o'); assertConverts("1", byte.class, (byte) 1); assertConverts("1_0", byte.class, (byte) 10); @@ -106,6 +111,54 @@ void convertsStringsToPrimitiveTypes() { assertConverts("42.2_3", double.class, 42.23); } + @Test + void convertsStringsToPrimitiveWrapperTypes() { + assertConverts("true", Boolean.class, true); + assertConverts("false", Boolean.class, false); + assertConverts("o", Character.class, 'o'); + assertConverts("1", Byte.class, (byte) 1); + assertConverts("1_0", Byte.class, (byte) 10); + assertConverts("1", Short.class, (short) 1); + assertConverts("1_2", Short.class, (short) 12); + assertConverts("42", Integer.class, 42); + assertConverts("700_050_000", Integer.class, 700_050_000); + assertConverts("42", Long.class, 42L); + assertConverts("4_2", Long.class, 42L); + assertConverts("42.23", Float.class, 42.23f); + assertConverts("42.2_3", Float.class, 42.23f); + assertConverts("42.23", Double.class, 42.23); + assertConverts("42.2_3", Double.class, 42.23); + } + + @Test + void convertsTheWordNullToBooleanFalse() { + assertConverts("null", boolean.class, false); + assertConverts("NULL", boolean.class, false); + assertConverts("null", Boolean.class, false); + assertConverts("NULL", Boolean.class, false); + } + + @ParameterizedTest(name = "[{index}] {0}") + @ValueSource(classes = { char.class, boolean.class, short.class, byte.class, int.class, long.class, float.class, + double.class }) + void throwsExceptionForNullToPrimitiveTypeConversion(Class type) { + assertThatExceptionOfType(ArgumentConversionException.class) // + .isThrownBy(() -> convert(null, type)) // + .withMessage("Cannot convert null to primitive value of type " + type.getCanonicalName()); + } + + @ParameterizedTest(name = "[{index}] {0}") + // NOTE: everything except Boolean.class and Character.class. + @ValueSource(classes = { Short.class, Byte.class, Integer.class, Long.class, Float.class, Double.class }) + void throwsExceptionWhenConvertingTheWordNullToPrimitiveWrapperType(Class type) { + assertThatExceptionOfType(ArgumentConversionException.class) // + .isThrownBy(() -> convert("null", type)) // + .withMessage("Failed to convert String \"null\" to type " + type.getCanonicalName()); + assertThatExceptionOfType(ArgumentConversionException.class) // + .isThrownBy(() -> convert("NULL", type)) // + .withMessage("Failed to convert String \"NULL\" to type " + type.getCanonicalName()); + } + @Test void throwsExceptionOnInvalidStringForPrimitiveTypes() { assertThatExceptionOfType(ArgumentConversionException.class) // diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/CsvArgumentsProviderTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/CsvArgumentsProviderTests.java index 767768ce6bac..e932451fa685 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/CsvArgumentsProviderTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/CsvArgumentsProviderTests.java @@ -248,11 +248,12 @@ void customEmptyValueAndDefaultNullValue() { @Test void customNullValues() { - var annotation = csvSource().nullValues("N/A", "NIL").lines("apple, , NIL, '', N/A, banana").build(); + var annotation = csvSource().nullValues("N/A", "NIL", "null")// + .lines("apple, , NIL, '', N/A, banana, null").build(); var arguments = provideArguments(annotation); - assertThat(arguments).containsExactly(array("apple", null, null, "", null, "banana")); + assertThat(arguments).containsExactly(array("apple", null, null, "", null, "banana", null)); } @Test From ab160b09d44efbb72ce28d50c15442dbfdf3dddd Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 22 Sep 2023 13:13:38 +0200 Subject: [PATCH 041/142] Update null/"null" conversion tests to reflect status quo in 5.10.x This commit updates the tests introduced in the last commit in order to align with the expected behavior in 5.10.x. See #3177 See #3472 --- .../ParameterizedTestIntegrationTests.java | 4 ++-- .../DefaultArgumentConverterTests.java | 24 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java index 78a5ed438582..7ccc5250604b 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestIntegrationTests.java @@ -116,14 +116,14 @@ class ParameterizedTestIntegrationTests { apple, True banana, true lemon, false - kumquat, null + kumquat, FALSE """) void sweetFruit(String fruit, Boolean sweet) { switch (fruit) { case "apple" -> assertThat(sweet).isTrue(); case "banana" -> assertThat(sweet).isTrue(); case "lemon" -> assertThat(sweet).isFalse(); - case "kumquat" -> assertThat(sweet).isFalse(); // "null" --> false + case "kumquat" -> assertThat(sweet).isFalse(); default -> fail("Unexpected fruit : " + fruit); } } diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java index d33645068d05..f801058f4e59 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java @@ -130,14 +130,6 @@ void convertsStringsToPrimitiveWrapperTypes() { assertConverts("42.2_3", Double.class, 42.23); } - @Test - void convertsTheWordNullToBooleanFalse() { - assertConverts("null", boolean.class, false); - assertConverts("NULL", boolean.class, false); - assertConverts("null", Boolean.class, false); - assertConverts("NULL", Boolean.class, false); - } - @ParameterizedTest(name = "[{index}] {0}") @ValueSource(classes = { char.class, boolean.class, short.class, byte.class, int.class, long.class, float.class, double.class }) @@ -148,8 +140,8 @@ void throwsExceptionForNullToPrimitiveTypeConversion(Class type) { } @ParameterizedTest(name = "[{index}] {0}") - // NOTE: everything except Boolean.class and Character.class. - @ValueSource(classes = { Short.class, Byte.class, Integer.class, Long.class, Float.class, Double.class }) + @ValueSource(classes = { Boolean.class, Character.class, Short.class, Byte.class, Integer.class, Long.class, + Float.class, Double.class }) void throwsExceptionWhenConvertingTheWordNullToPrimitiveWrapperType(Class type) { assertThatExceptionOfType(ArgumentConversionException.class) // .isThrownBy(() -> convert("null", type)) // @@ -172,6 +164,18 @@ void throwsExceptionOnInvalidStringForPrimitiveTypes() { .withMessage("Failed to convert String \"tru\" to type boolean") // .havingCause() // .withMessage("String must be 'true' or 'false' (ignoring case): tru"); + + assertThatExceptionOfType(ArgumentConversionException.class) // + .isThrownBy(() -> convert("null", boolean.class)) // + .withMessage("Failed to convert String \"null\" to type boolean") // + .havingCause() // + .withMessage("String must be 'true' or 'false' (ignoring case): null"); + + assertThatExceptionOfType(ArgumentConversionException.class) // + .isThrownBy(() -> convert("NULL", boolean.class)) // + .withMessage("Failed to convert String \"NULL\" to type boolean") // + .havingCause() // + .withMessage("String must be 'true' or 'false' (ignoring case): NULL"); } @Test From 7c99561026b019ecedf9cb080306ae4809701bea Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 22 Sep 2023 10:47:53 -0700 Subject: [PATCH 042/142] Upgradle to 8.4-rc-1 --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- gradlew | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 864d6c47512b..56c832da783d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=591855b517fc635b9e04de1d05d5e76ada3f89f5fc76f87978d1b245b4f69225 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionSha256Sum=7eec87a597388fb67df02d0cc4f8bc566abd5adf5838dab1f4db0e83fa96bd4f +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-rc-1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 0adc8e1a5321..1aa94a426907 100755 --- a/gradlew +++ b/gradlew @@ -145,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ From 0876ceab2276511c96b35b6f52ddbd074c672304 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Mon, 25 Sep 2023 11:07:15 +0200 Subject: [PATCH 043/142] Remove JDK 20 from cross-version testing matrix --- .github/workflows/cross-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cross-version.yml b/.github/workflows/cross-version.yml index 8c96b261d081..5a9a309ab286 100644 --- a/.github/workflows/cross-version.yml +++ b/.github/workflows/cross-version.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - jdk: [20, 21, 22] + jdk: [21, 22] name: "OpenJDK ${{ matrix.jdk }}" runs-on: ubuntu-latest steps: From fce00e7e7cf92e25be68f3219c647af1b27ce0fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:08:43 +0000 Subject: [PATCH 044/142] Bump org.apache.groovy:groovy from 4.0.13 to 4.0.15 Bumps [org.apache.groovy:groovy](https://github.com/apache/groovy) from 4.0.13 to 4.0.15. - [Commits](https://github.com/apache/groovy/commits) --- updated-dependencies: - dependency-name: org.apache.groovy:groovy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e052d68fd896..6b6f31c89ccf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -38,7 +38,7 @@ gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.21.0" } gradle-versions = { module = "com.github.ben-manes:gradle-versions-plugin", version.ref = "gradleVersionsPlugin" } -groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.13" } +groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.15" } groovy2-bom = { module = "org.codehaus.groovy:groovy-bom", version = "2.5.21" } hamcrest = { module = "org.hamcrest:hamcrest", version = "2.2" } jfrunit = { module = "org.moditect.jfrunit:jfrunit-core", version = "1.0.0.Alpha2" } From 2b3ddb21011b6518afece3f45f01b394f4f51ef7 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Mon, 25 Sep 2023 17:09:10 +0200 Subject: [PATCH 045/142] Disable `kotlinSourcesJar` Gradle task Fixes #3474. --- .../kotlin/junitbuild.kotlin-library-conventions.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gradle/plugins/common/src/main/kotlin/junitbuild.kotlin-library-conventions.gradle.kts b/gradle/plugins/common/src/main/kotlin/junitbuild.kotlin-library-conventions.gradle.kts index 8f25bde2c0dd..7ae9944b015c 100644 --- a/gradle/plugins/common/src/main/kotlin/junitbuild.kotlin-library-conventions.gradle.kts +++ b/gradle/plugins/common/src/main/kotlin/junitbuild.kotlin-library-conventions.gradle.kts @@ -5,6 +5,10 @@ plugins { kotlin("jvm") } +tasks.named("kotlinSourcesJar") { + enabled = false +} + tasks.withType().configureEach { kotlinOptions { apiVersion = "1.6" From 073223fa12bc47aed487920cf2e065425a59f8b4 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Mon, 2 Oct 2023 08:30:53 +0200 Subject: [PATCH 046/142] Upgradle to 8.4-rc-3 --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 56c832da783d..15dd4b0c2593 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=7eec87a597388fb67df02d0cc4f8bc566abd5adf5838dab1f4db0e83fa96bd4f -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-rc-1-bin.zip +distributionSha256Sum=cb1945fa73552ddf99cf32ec2fcd065771fcb6bf4a366b9408e79f9561601853 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-rc-3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 6b3b8a3d4aaa2c77c556003ae30af1e9627232af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 05:36:12 +0000 Subject: [PATCH 047/142] Bump com.diffplug.spotless:spotless-plugin-gradle from 6.21.0 to 6.22.0 Bumps [com.diffplug.spotless:spotless-plugin-gradle](https://github.com/diffplug/spotless) from 6.21.0 to 6.22.0. - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](https://github.com/diffplug/spotless/compare/gradle/6.21.0...gradle/6.22.0) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-plugin-gradle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6b6f31c89ccf..3f8d331775dd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,7 +36,7 @@ gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", vers gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } -gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.21.0" } +gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.22.0" } gradle-versions = { module = "com.github.ben-manes:gradle-versions-plugin", version.ref = "gradleVersionsPlugin" } groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.15" } groovy2-bom = { module = "org.codehaus.groovy:groovy-bom", version = "2.5.21" } From a5d5e6e979a486dfcd145f5cc3aac8c766bfc065 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 05:36:37 +0000 Subject: [PATCH 048/142] Bump com.puppycrawl.tools:checkstyle from 10.12.3 to 10.12.4 Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 10.12.3 to 10.12.4. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.3...checkstyle-10.12.4) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3f8d331775dd..86e5b7b6add4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ asciidoctor-pdf = "1.5.3" asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gradle.kts can be removed when upgrading assertj = "3.24.2" bnd = "6.4.0" -checkstyle = "10.12.3" +checkstyle = "10.12.4" gradleVersionsPlugin = "0.48.0" jacoco = "0.8.7" jmh = "1.37" From 71798ca59488362164123053e51f9c28abdcaf16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 05:36:41 +0000 Subject: [PATCH 049/142] Bump com.gradle:common-custom-user-data-gradle-plugin Bumps com.gradle:common-custom-user-data-gradle-plugin from 1.11.2 to 1.11.3. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 86e5b7b6add4..b0ba80db8f67 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.162" } commons-io = { module = "commons-io:commons-io", version = "2.13.0" } -gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.2" } +gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.3" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } From 449937465e9ef0ce0d7b71fc7df3f9bf64fb5def Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Oct 2023 06:31:53 +0000 Subject: [PATCH 050/142] Bump commons-io:commons-io from 2.13.0 to 2.14.0 Bumps commons-io:commons-io from 2.13.0 to 2.14.0. --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b0ba80db8f67..14dbc55e57cc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.162" } -commons-io = { module = "commons-io:commons-io", version = "2.13.0" } +commons-io = { module = "commons-io:commons-io", version = "2.14.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.3" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15" } From 3c8f437f36735ba0ed042daee95a4bc9f50044cd Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 3 Oct 2023 11:26:56 +0200 Subject: [PATCH 051/142] Disable documentation checksum check for now To diagnose issues with the component diagram --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index afde23101ed5..3a890b586391 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -105,6 +105,6 @@ jobs: with: arguments: --quiet - name: Upload Documentation - env: - GRGIT_USER: ${{ secrets.GH_TOKEN }} - run: ./gradle/scripts/publishDocumentationSnapshotOnlyIfNecessary.sh + uses: ./.github/actions/run-gradle + with: + arguments: gitPublishPush -Dscan.tag.Documentation From 8cfe93b6fa5fc72b1c6e654b7c2857d15274ec40 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 3 Oct 2023 11:35:27 +0200 Subject: [PATCH 052/142] Gradle Enterprise -> Develocity --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 43f900ade772..78fb026ea940 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,14 @@ A code coverage report can also be generated locally via the [Gradle Wrapper] by executing `./gradlew -Ptesting.enableJaCoCo clean jacocoRootReport`. The results will be available in `build/reports/jacoco/jacocoRootReport/html/index.html`. -## Gradle Enterprise +## Develocity -[![Revved up by Gradle Enterprise](https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?logo=Gradle&labelColor=02303A)](https://ge.junit.org/scans) +[![Revved up by Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A)](https://ge.junit.org/scans) -JUnit 5 utilizes [Gradle Enterprise](https://gradle.com/) for _Build Scans_, _Build Cache_, and _Test Distribution_. +JUnit 5 utilizes [Develocity](https://gradle.com/) for [Build Scans](https://scans.gradle.com/), +[Build Cache](https://docs.gradle.org/current/userguide/build_cache.html), +[Predictive Test Selection](https://docs.gradle.com/enterprise/predictive-test-selection/), and +[Test Distribution](https://docs.gradle.com/enterprise/test-distribution/). The latest Build Scans are available on [ge.junit.org](https://ge.junit.org/). Currently, only core team members can publish Build Scans and use Test Distribution on that server. From 54b07d52e09316fb9837c5bacd40f381f74ffd43 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 3 Oct 2023 11:42:05 +0200 Subject: [PATCH 053/142] Remove unnecessary build step --- .github/workflows/main.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a890b586391..9ed1c0e4ce66 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -100,10 +100,6 @@ jobs: run: | sudo apt-get update sudo apt-get install graphviz - - name: Restore Gradle cache and display toolchains - uses: ./.github/actions/run-gradle - with: - arguments: --quiet - name: Upload Documentation uses: ./.github/actions/run-gradle with: From ca5f02bb134abf71367964bec4fb204d9572c5d0 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 3 Oct 2023 11:42:25 +0200 Subject: [PATCH 054/142] Inject GitHub token again --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9ed1c0e4ce66..0fef409ed53d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -104,3 +104,5 @@ jobs: uses: ./.github/actions/run-gradle with: arguments: gitPublishPush -Dscan.tag.Documentation + env: + GRGIT_USER: ${{ secrets.GH_TOKEN }} From 4fdbc6f319915a882cbedbe79f15255af695dfd8 Mon Sep 17 00:00:00 2001 From: JUnit Team Date: Thu, 5 Oct 2023 00:31:58 +0000 Subject: [PATCH 055/142] Bump Gradle Wrapper from 8.4-rc-3 to 8.4 --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 15dd4b0c2593..46671acb6e14 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=cb1945fa73552ddf99cf32ec2fcd065771fcb6bf4a366b9408e79f9561601853 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-rc-3-bin.zip +distributionSha256Sum=3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From bc7df60d6276b6236867070e0fed1da5960c086b Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Thu, 5 Oct 2023 17:02:00 +0200 Subject: [PATCH 056/142] Disable linking to javadoc.io since the site is down Related issue: maxcellent/javadoc.io#180 --- documentation/documentation.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index fd4877cdd6fc..85d8f6064884 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -112,7 +112,7 @@ val jdkJavadocBaseUrl = "https://docs.oracle.com/en/java/javase/11/docs/api" val elementListsDir = layout.buildDirectory.dir("elementLists") val externalModulesWithoutModularJavadoc = mapOf( "org.apiguardian.api" to "https://apiguardian-team.github.io/apiguardian/docs/$apiGuardianDocVersion/api/", - "org.assertj.core" to "https://javadoc.io/doc/org.assertj/assertj-core/${libs.versions.assertj.get()}/", +// "org.assertj.core" to "https://javadoc.io/doc/org.assertj/assertj-core/${libs.versions.assertj.get()}/", // https://github.com/maxcellent/javadoc.io/issues/180 "org.opentest4j" to "https://ota4j-team.github.io/opentest4j/docs/$ota4jDocVersion/api/" ) require(externalModulesWithoutModularJavadoc.values.all { it.endsWith("/") }) { From 2619aee25745c8ff789c62aa7c871b7ca42a785c Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Thu, 5 Oct 2023 17:35:37 +0200 Subject: [PATCH 057/142] Fix component diagram (#3487) * Add check for component diagram * Use latest version of asciidoctorj-diagram and asciidoctorj-pdf * Declare asccidoctorj artifacts in version catalog for Dependabot updates --- documentation/documentation.gradle.kts | 10 ++++++++-- gradle/libs.versions.toml | 7 ++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index 85d8f6064884..89f87a5079f5 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -63,8 +63,8 @@ dependencies { asciidoctorj { modules { - diagram.use() - pdf.version(libs.versions.asciidoctor.pdf) + diagram.version(libs.versions.asciidoctorj.diagram) + pdf.version(libs.versions.asciidoctorj.pdf) } requires(file("src/docs/asciidoc/resources/themes/rouge_junit.rb")) } @@ -297,6 +297,12 @@ tasks { "userGuidePdfFileName" to userGuidePdfFileName, "releaseNotesUrl" to "../release-notes/index.html#release-notes" )) + doLast { + val componentDiagramSvg = outputDirProperty.file("user-guide/images/component-diagram.svg").get().asFile + require(componentDiagramSvg.exists()) { + "Component diagram was not generated at $componentDiagramSvg" + } + } } asciidoctorPdf { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 14dbc55e57cc..c5a9e97054fa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,8 @@ [versions] ant = "1.10.14" apiguardian = "1.1.2" -asciidoctor-pdf = "1.5.3" +asciidoctorj-diagram = "2.2.9" +asciidoctorj-pdf = "2.3.9" asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gradle.kts can be removed when upgrading assertj = "3.24.2" bnd = "6.4.0" @@ -65,6 +66,10 @@ xmlunit-assertj = { module = "org.xmlunit:xmlunit-assertj3", version.ref = "xmlu xmlunit-placeholders = { module = "org.xmlunit:xmlunit-placeholders", version.ref = "xmlunit" } testingAnnotations = { module = "com.gradle:gradle-enterprise-testing-annotations", version = "1.1.1" } +# These are only declared here so Dependabot knows when to update the referenced versions +asciidoctorj-diagram = { module = "org.asciidoctor:asciidoctorj-diagram", version.ref = "asciidoctorj-diagram" } +asciidoctorj-pdf = { module = "org.asciidoctor:asciidoctorj-pdf", version.ref = "asciidoctorj-pdf" } + [bundles] ant = ["ant", "ant-junit", "ant-junitlauncher"] log4j = ["log4j-core", "log4j-jul"] From 3a3c20f5ba35ef0cc4055f7f335e817197e4e1df Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Thu, 5 Oct 2023 17:49:04 +0200 Subject: [PATCH 058/142] Disable Asciidoctor last update label to avoid unnecessary deployments --- documentation/src/docs/asciidoc/release-notes/index.adoc | 1 + documentation/src/docs/asciidoc/user-guide/index.adoc | 1 + 2 files changed, 2 insertions(+) diff --git a/documentation/src/docs/asciidoc/release-notes/index.adoc b/documentation/src/docs/asciidoc/release-notes/index.adoc index 952c742a86d3..bc63c1a43fcf 100644 --- a/documentation/src/docs/asciidoc/release-notes/index.adoc +++ b/documentation/src/docs/asciidoc/release-notes/index.adoc @@ -6,6 +6,7 @@ Stefan Bechtold; Sam Brannen; Johannes Link; Matthias Merdes; Marc Philipp; Juli :docinfodir: {includedir}/docinfos :docinfo2: :numbered!: +:last-update-label!: // This document contains the _change log_ for all JUnit 5 releases since 5.10 GA. diff --git a/documentation/src/docs/asciidoc/user-guide/index.adoc b/documentation/src/docs/asciidoc/user-guide/index.adoc index 57e0f30948e0..9c34f8d33739 100644 --- a/documentation/src/docs/asciidoc/user-guide/index.adoc +++ b/documentation/src/docs/asciidoc/user-guide/index.adoc @@ -16,6 +16,7 @@ ifdef::backend-pdf[:imagesdir: {imagesoutdir}] // :sectnums: :toclevels: 4 +:last-update-label!: // include::{includedir}/link-attributes.adoc[] From 3f8f07575ca5468b5fab8701637a66a7a1a470d5 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Thu, 5 Oct 2023 17:49:35 +0200 Subject: [PATCH 059/142] Delete unused script --- ...ishDocumentationSnapshotOnlyIfNecessary.sh | 62 ------------------- 1 file changed, 62 deletions(-) delete mode 100755 gradle/scripts/publishDocumentationSnapshotOnlyIfNecessary.sh diff --git a/gradle/scripts/publishDocumentationSnapshotOnlyIfNecessary.sh b/gradle/scripts/publishDocumentationSnapshotOnlyIfNecessary.sh deleted file mode 100755 index ecd0482a2368..000000000000 --- a/gradle/scripts/publishDocumentationSnapshotOnlyIfNecessary.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash - -readonly checksum_directory='documentation/build/checksum' -readonly current="${checksum_directory}/current-checksum.txt" -readonly published="${checksum_directory}/published-checksum.txt" -readonly github_pages_url='https://raw.githubusercontent.com/junit-team/junit5/gh-pages/docs/snapshot/published-checksum.txt' - -# -# always generate current sums -# -echo "Generating checksum file ${current}..." -mkdir --parents "${checksum_directory}" -md5sum documentation/documentation.gradle.kts > "${current}" -md5sum $(find documentation/src -type f) >> "${current}" -# skip module junit-bom because it doesn't contain relevant documentation -md5sum $(find junit-jupiter -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-jupiter-api -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-jupiter-engine -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-jupiter-migrationsupport -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-jupiter-params -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-commons -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-console -wholename '**/src/main/*.java') >> "${current}" -# skip module junit-platform-console-standalone because it doesn't contain relevant documentation -md5sum $(find junit-platform-engine -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-jfr -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-launcher -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-reporting -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-runner -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-suite -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-suite-api -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-suite-commons -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-suite-engine -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-platform-testkit -wholename '**/src/main/*.java') >> "${current}" -md5sum $(find junit-vintage-engine -wholename '**/src/main/*.java') >> "${current}" -# skip module platform-tests because it doesn't contain relevant documentation -# skip module platform-tooling-support-tests because it doesn't contain relevant documentation -sort --output "${current}" "${current}" -echo -md5sum "${current}" - -# -# compare current with published sums -# -curl --silent --output "${published}" "${github_pages_url}" -md5sum "${published}" -if cmp --silent "${current}" "${published}" ; then - # - # no changes detected: we're done - # - echo - echo "Already published documentation with same source checksum." - echo -else - # - # update checksum file and trigger new documentation build and upload - # - echo - echo "Creating and publishing documentation..." - echo - cp --force "${current}" "${published}" - ./gradlew gitPublishPush -Porg.gradle.java.installations.auto-download=false -Dscan.tag.Documentation -fi From 1301818eb28d6081b6ea982d9f5c3cece4f481d0 Mon Sep 17 00:00:00 2001 From: "pixeebot[bot]" <23113631+pixeebot@users.noreply.github.com> Date: Sat, 7 Oct 2023 09:17:12 +0000 Subject: [PATCH 060/142] Switch order of literals to prevent NullPointerException --- .../java/org/junit/platform/commons/util/CloseablePath.java | 2 +- .../src/main/java/org/junit/platform/engine/UniqueId.java | 2 +- .../org/junit/platform/launcher/core/EngineIdValidator.java | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java index 58ad17ce39c7..3f7af1ddd407 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/CloseablePath.java @@ -59,7 +59,7 @@ static CloseablePath create(URI uri, FileSystemProvider fileSystemProvider) thro return createForJarFileSystem(new URI(jarUri), fileSystem -> fileSystem.getPath(jarEntry), fileSystemProvider); } - if (uri.getScheme().equals(FILE_URI_SCHEME) && uri.getPath().endsWith(JAR_FILE_EXTENSION)) { + if (FILE_URI_SCHEME.equals(uri.getScheme()) && uri.getPath().endsWith(JAR_FILE_EXTENSION)) { return createForJarFileSystem(new URI(JAR_URI_SCHEME + ':' + uri), fileSystem -> fileSystem.getRootDirectories().iterator().next(), fileSystemProvider); } diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueId.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueId.java index 5e4f13b99661..f60e0db8b588 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueId.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/UniqueId.java @@ -118,7 +118,7 @@ final Optional getRoot() { * @see #forEngine(String) */ public final Optional getEngineId() { - return getRoot().filter(segment -> segment.getType().equals(ENGINE_SEGMENT_TYPE)).map(Segment::getValue); + return getRoot().filter(segment -> ENGINE_SEGMENT_TYPE.equals(segment.getType())).map(Segment::getValue); } /** diff --git a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java index abeeb298acaa..47e379b42bf0 100644 --- a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java +++ b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java @@ -56,15 +56,15 @@ private static boolean validateReservedIds(TestEngine testEngine) { if (!engineId.startsWith("junit-")) { return true; } - if (engineId.equals("junit-jupiter")) { + if ("junit-jupiter".equals(engineId)) { validateWellKnownClassName(testEngine, "org.junit.jupiter.engine.JupiterTestEngine"); return true; } - if (engineId.equals("junit-vintage")) { + if ("junit-vintage".equals(engineId)) { validateWellKnownClassName(testEngine, "org.junit.vintage.engine.VintageTestEngine"); return true; } - if (engineId.equals("junit-platform-suite")) { + if ("junit-platform-suite".equals(engineId)) { validateWellKnownClassName(testEngine, "org.junit.platform.suite.engine.SuiteTestEngine"); return true; } From 28981647939d280c19719107ef0e1403e66de25f Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 8 Oct 2023 11:46:06 +0200 Subject: [PATCH 061/142] Improve Javadoc for TestEngine#getId() --- .../src/main/java/org/junit/platform/engine/TestEngine.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/TestEngine.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/TestEngine.java index 401fa19363c8..930b817e1b92 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/TestEngine.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/TestEngine.java @@ -54,6 +54,8 @@ public interface TestEngine { * and JUnit Jupiter use {@code "junit-vintage"} and {@code "junit-jupiter"}, * respectively. When in doubt, you may use the fully qualified name of your * custom {@code TestEngine} implementation class. + * + * @return the ID of this test engine; never {@code null} or blank */ String getId(); From 941f80d6a8cccdb1f08b69eedf061f41faa147e9 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 8 Oct 2023 11:56:41 +0200 Subject: [PATCH 062/142] Polish EngineIdValidator --- .../launcher/core/EngineIdValidator.java | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java index 47e379b42bf0..77ff53d83af7 100644 --- a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java +++ b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/EngineIdValidator.java @@ -16,6 +16,7 @@ import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.logging.Logger; import org.junit.platform.commons.logging.LoggerFactory; +import org.junit.platform.commons.util.Preconditions; import org.junit.platform.engine.TestEngine; /** @@ -29,7 +30,7 @@ private EngineIdValidator() { static Iterable validate(Iterable testEngines) { Set ids = new HashSet<>(); for (TestEngine testEngine : testEngines) { - // check usage of reserved id prefix + // check usage of reserved ID prefix if (!validateReservedIds(testEngine)) { getLogger().warn(() -> String.format( "Third-party TestEngine implementations are forbidden to use the reserved 'junit-' prefix for their ID: '%s'", @@ -52,23 +53,27 @@ private static Logger getLogger() { // https://github.com/junit-team/junit5/issues/1557 private static boolean validateReservedIds(TestEngine testEngine) { - String engineId = testEngine.getId(); + String engineId = Preconditions.notBlank(testEngine.getId(), + () -> String.format("ID for TestEngine [%s] must not be null or blank", testEngine.getClass().getName())); if (!engineId.startsWith("junit-")) { return true; } - if ("junit-jupiter".equals(engineId)) { - validateWellKnownClassName(testEngine, "org.junit.jupiter.engine.JupiterTestEngine"); - return true; - } - if ("junit-vintage".equals(engineId)) { - validateWellKnownClassName(testEngine, "org.junit.vintage.engine.VintageTestEngine"); - return true; - } - if ("junit-platform-suite".equals(engineId)) { - validateWellKnownClassName(testEngine, "org.junit.platform.suite.engine.SuiteTestEngine"); - return true; + switch (engineId) { + case "junit-jupiter": { + validateWellKnownClassName(testEngine, "org.junit.jupiter.engine.JupiterTestEngine"); + return true; + } + case "junit-vintage": { + validateWellKnownClassName(testEngine, "org.junit.vintage.engine.VintageTestEngine"); + return true; + } + case "junit-platform-suite": { + validateWellKnownClassName(testEngine, "org.junit.platform.suite.engine.SuiteTestEngine"); + return true; + } + default: + return false; } - return false; } private static void validateWellKnownClassName(TestEngine testEngine, String expectedClassName) { @@ -80,4 +85,5 @@ private static void validateWellKnownClassName(TestEngine testEngine, String exp String.format("Third-party TestEngine '%s' is forbidden to use the reserved '%s' TestEngine ID.", actualClassName, testEngine.getId())); } + } From 3edd5f7f31c51b7dd8db31294f1b9475b5cd9d04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 05:43:13 +0000 Subject: [PATCH 063/142] Bump org.apache.maven:apache-maven from 3.9.4 to 3.9.5 Bumps [org.apache.maven:apache-maven](https://github.com/apache/maven) from 3.9.4 to 3.9.5. - [Release notes](https://github.com/apache/maven/releases) - [Commits](https://github.com/apache/maven/compare/maven-3.9.4...maven-3.9.5) --- updated-dependencies: - dependency-name: org.apache.maven:apache-maven dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c5a9e97054fa..93e27df969a3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -51,7 +51,7 @@ junit4 = { module = "junit:junit", version = { require = "[4.12,)", prefer = "4. kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.7.3" } log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4j" } -maven = { module = "org.apache.maven:apache-maven", version = "3.9.4" } +maven = { module = "org.apache.maven:apache-maven", version = "3.9.5" } mavenSurefirePlugin = { module = "org.apache.maven.plugins:maven-surefire-plugin", version.ref = "surefire" } memoryfilesystem = { module = "com.github.marschall:memoryfilesystem", version = "2.6.1" } mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.5.0" } From 3944cdf8027a21277726d1e09fe11a8da610b798 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 05:43:41 +0000 Subject: [PATCH 064/142] Bump org.mockito:mockito-junit-jupiter from 5.5.0 to 5.6.0 Bumps [org.mockito:mockito-junit-jupiter](https://github.com/mockito/mockito) from 5.5.0 to 5.6.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.5.0...v5.6.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 93e27df969a3..76667e0f3356 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -54,7 +54,7 @@ log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4 maven = { module = "org.apache.maven:apache-maven", version = "3.9.5" } mavenSurefirePlugin = { module = "org.apache.maven.plugins:maven-surefire-plugin", version.ref = "surefire" } memoryfilesystem = { module = "com.github.marschall:memoryfilesystem", version = "2.6.1" } -mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.5.0" } +mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.6.0" } opentest4j = { module = "org.opentest4j:opentest4j", version.ref = "opentest4j" } openTestReporting-events = { module = "org.opentest4j.reporting:open-test-reporting-events", version.ref = "openTestReporting" } openTestReporting-tooling = { module = "org.opentest4j.reporting:open-test-reporting-tooling", version.ref = "openTestReporting" } From f9ae7f6448df24d3bd60741475f5e8f543b3f535 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 05:43:49 +0000 Subject: [PATCH 065/142] Bump com.gradle:gradle-enterprise-testing-annotations Bumps [com.gradle:gradle-enterprise-testing-annotations](https://github.com/gradle/gradle-enterprise-testing-annotations) from 1.1.1 to 1.1.2. - [Release notes](https://github.com/gradle/gradle-enterprise-testing-annotations/releases) - [Commits](https://github.com/gradle/gradle-enterprise-testing-annotations/compare/1.1.1...1.1.2) --- updated-dependencies: - dependency-name: com.gradle:gradle-enterprise-testing-annotations dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 76667e0f3356..76bc3cc1793b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,7 +64,7 @@ spock1 = { module = "org.spockframework:spock-core", version = "1.3-groovy-2.5" univocity-parsers = { module = "com.univocity:univocity-parsers", version = "2.9.1" } xmlunit-assertj = { module = "org.xmlunit:xmlunit-assertj3", version.ref = "xmlunit" } xmlunit-placeholders = { module = "org.xmlunit:xmlunit-placeholders", version.ref = "xmlunit" } -testingAnnotations = { module = "com.gradle:gradle-enterprise-testing-annotations", version = "1.1.1" } +testingAnnotations = { module = "com.gradle:gradle-enterprise-testing-annotations", version = "1.1.2" } # These are only declared here so Dependabot knows when to update the referenced versions asciidoctorj-diagram = { module = "org.asciidoctor:asciidoctorj-diagram", version.ref = "asciidoctorj-diagram" } From dfa8659d6a1da274ecc293be073fd9a02241ca76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 05:57:10 +0000 Subject: [PATCH 066/142] Bump gradleVersionsPlugin from 0.48.0 to 0.49.0 Bumps `gradleVersionsPlugin` from 0.48.0 to 0.49.0. Updates `com.github.ben-manes:gradle-versions-plugin` from 0.48.0 to 0.49.0 - [Release notes](https://github.com/ben-manes/gradle-versions-plugin/releases) - [Commits](https://github.com/ben-manes/gradle-versions-plugin/compare/v0.48.0...v0.49.0) Updates `com.github.ben-manes.versions` from 0.48.0 to 0.49.0 --- updated-dependencies: - dependency-name: com.github.ben-manes:gradle-versions-plugin dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.github.ben-manes.versions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 76bc3cc1793b..91dbd92dbdfb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gra assertj = "3.24.2" bnd = "6.4.0" checkstyle = "10.12.4" -gradleVersionsPlugin = "0.48.0" +gradleVersionsPlugin = "0.49.0" jacoco = "0.8.7" jmh = "1.37" junit4 = "4.13.2" From 6b34cdd0efea18143cd415b1530b050b9074d316 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 05:56:55 +0000 Subject: [PATCH 067/142] Bump bnd from 6.4.0 to 7.0.0 Bumps `bnd` from 6.4.0 to 7.0.0. Updates `biz.aQute.bnd:biz.aQute.bndlib` from 6.4.0 to 7.0.0 - [Release notes](https://github.com/bndtools/bnd/releases) - [Changelog](https://github.com/bndtools/bnd/blob/master/docs/ADDING_RELEASE_DOCS.md) - [Commits](https://github.com/bndtools/bnd/compare/6.4.0...7.0.0) Updates `biz.aQute.bnd:biz.aQute.bnd.gradle` from 6.4.0 to 7.0.0 - [Release notes](https://github.com/bndtools/bnd/releases) - [Changelog](https://github.com/bndtools/bnd/blob/master/docs/ADDING_RELEASE_DOCS.md) - [Commits](https://github.com/bndtools/bnd/compare/6.4.0...7.0.0) --- updated-dependencies: - dependency-name: biz.aQute.bnd:biz.aQute.bndlib dependency-type: direct:production update-type: version-update:semver-major - dependency-name: biz.aQute.bnd:biz.aQute.bnd.gradle dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 91dbd92dbdfb..0eebc69fe3e9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ asciidoctorj-diagram = "2.2.9" asciidoctorj-pdf = "2.3.9" asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gradle.kts can be removed when upgrading assertj = "3.24.2" -bnd = "6.4.0" +bnd = "7.0.0" checkstyle = "10.12.4" gradleVersionsPlugin = "0.49.0" jacoco = "0.8.7" From 2f75deb293ec538ea736931d049f648abc6b7e1a Mon Sep 17 00:00:00 2001 From: Andrei Rybak Date: Fri, 13 Oct 2023 12:57:33 +0200 Subject: [PATCH 068/142] Drop duplicate `isSnapshot` variable in Gradle build script (#3413) Publishing conventions plugin calculates `isSnapshot`: isSnapshot = project.version.toString().contains("SNAPSHOT") twice: 1. at the top of build script junitbuild.publishing-conventions.gradle.kts 2. in configuration of `Sign` tasks. Drop the second `val isSnapshot` to make `Sign` task configuration re-use the variable from the top of the script. --- .../src/main/kotlin/junitbuild.publishing-conventions.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/gradle/plugins/common/src/main/kotlin/junitbuild.publishing-conventions.gradle.kts b/gradle/plugins/common/src/main/kotlin/junitbuild.publishing-conventions.gradle.kts index bab950933c2a..44d693b44779 100644 --- a/gradle/plugins/common/src/main/kotlin/junitbuild.publishing-conventions.gradle.kts +++ b/gradle/plugins/common/src/main/kotlin/junitbuild.publishing-conventions.gradle.kts @@ -47,7 +47,6 @@ signing { } tasks.withType().configureEach { - val isSnapshot = project.version.toString().contains("SNAPSHOT") onlyIf { !isSnapshot // Gradle Module Metadata currently does not support signing snapshots } From e4a39800abd2e80422d77ce9a99cfad2ba2858c0 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 6 Oct 2023 14:49:17 +0200 Subject: [PATCH 069/142] Revert "Disable linking to javadoc.io since the site is down" This reverts commit bc7df60d6276b6236867070e0fed1da5960c086b. --- documentation/documentation.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index 89f87a5079f5..da73ae62b0e7 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -112,7 +112,7 @@ val jdkJavadocBaseUrl = "https://docs.oracle.com/en/java/javase/11/docs/api" val elementListsDir = layout.buildDirectory.dir("elementLists") val externalModulesWithoutModularJavadoc = mapOf( "org.apiguardian.api" to "https://apiguardian-team.github.io/apiguardian/docs/$apiGuardianDocVersion/api/", -// "org.assertj.core" to "https://javadoc.io/doc/org.assertj/assertj-core/${libs.versions.assertj.get()}/", // https://github.com/maxcellent/javadoc.io/issues/180 + "org.assertj.core" to "https://javadoc.io/doc/org.assertj/assertj-core/${libs.versions.assertj.get()}/", "org.opentest4j" to "https://ota4j-team.github.io/opentest4j/docs/$ota4jDocVersion/api/" ) require(externalModulesWithoutModularJavadoc.values.all { it.endsWith("/") }) { From 9af6ca4ba66e5bc3ba4a93b47333816853dd34f4 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 13 Oct 2023 15:27:49 +0200 Subject: [PATCH 070/142] Stop logging exceptions thrown from ExtensionContext.close() Prior to this commit such exceptions were logged and rethrown which caused them to be reported twice: once in the log and once as part of the test failure. Fixes #3422. --- .../JupiterEngineExecutionContext.java | 3 +-- .../CloseableResourceIntegrationTests.java | 6 +++++- .../JupiterEngineExecutionContextTests.java | 19 ++++++------------- .../TempDirectoryPerDeclarationTests.java | 13 ++++++++----- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java index a31c9c02ad27..81c38308563d 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java @@ -53,8 +53,7 @@ public void close() throws Exception { ((AutoCloseable) extensionContext).close(); } catch (Exception e) { - logger.error(e, () -> "Caught exception while closing extension context: " + extensionContext); - throw e; + throw new JUnitException("Failed to close extension context", e); } } } diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/extension/CloseableResourceIntegrationTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/extension/CloseableResourceIntegrationTests.java index f96e1b6341d2..bdb5ac2e82d8 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/extension/CloseableResourceIntegrationTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/extension/CloseableResourceIntegrationTests.java @@ -15,6 +15,7 @@ import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; import static org.junit.platform.testkit.engine.EventConditions.reportEntry; import static org.junit.platform.testkit.engine.EventConditions.test; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.cause; import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; import static org.junit.platform.testkit.engine.TestExecutionResultConditions.suppressed; @@ -57,7 +58,10 @@ void exceptionsDuringCloseAreReportedAsSuppressed() { test(), // finishedWithFailure( // message("Exception in test"), // - suppressed(0, message("Exception in onClose"))))); + suppressed(0, // + message("Failed to close extension context"), // + cause(message("Exception in onClose")) // + )))); } @ExtendWith(ThrowingOnCloseExtension.class) diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContextTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContextTests.java index d6e619d886bd..f7dbaf4316d3 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContextTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContextTests.java @@ -17,15 +17,10 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.withSettings; -import java.util.logging.Level; -import java.util.logging.LogRecord; - import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.extension.MutableExtensionRegistry; -import org.junit.platform.commons.logging.LogRecordListener; import org.junit.platform.engine.EngineExecutionListener; /** @@ -89,12 +84,11 @@ void canOverrideAttributeWhenContextIsExtended() { } @Test - @TrackLogRecords - void closeAttemptExceptionWillBeThrownDownTheCallStack(LogRecordListener logRecordListener) throws Exception { + void closeAttemptExceptionWillBeThrownDownTheCallStack() throws Exception { ExtensionContext failingExtensionContext = mock(ExtensionContext.class, withSettings().extraInterfaces(AutoCloseable.class)); - Exception expectedException = new Exception("test message"); - doThrow(expectedException).when(((AutoCloseable) failingExtensionContext)).close(); + Exception expectedCause = new Exception("test message"); + doThrow(expectedCause).when(((AutoCloseable) failingExtensionContext)).close(); JupiterEngineExecutionContext newContext = originalContext.extend() // .withExtensionContext(failingExtensionContext) // @@ -102,10 +96,9 @@ void closeAttemptExceptionWillBeThrownDownTheCallStack(LogRecordListener logReco Exception actualException = assertThrows(Exception.class, newContext::close); - assertSame(expectedException, actualException); - assertThat(logRecordListener.stream(JupiterEngineExecutionContext.class, Level.SEVERE)) // - .extracting(LogRecord::getMessage) // - .containsOnly("Caught exception while closing extension context: " + failingExtensionContext); + assertThat(actualException) // + .hasMessage("Failed to close extension context") // + .hasCauseReference(expectedCause); } } diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerDeclarationTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerDeclarationTests.java index f0575de592c0..458e433a1f8b 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerDeclarationTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerDeclarationTests.java @@ -230,11 +230,14 @@ private void onlyAttemptsToDeleteUndeletablePathOnce(Class Path.of(it.getKeyValuePairs().get(UndeletableTestCase.TEMP_DIR))).findAny().orElseThrow(); assertSingleFailedTest(results, // - instanceOf(IOException.class), // - message("Failed to delete temp directory " + tempDir.toAbsolutePath() + ". " + // - "The following paths could not be deleted (see suppressed exceptions for details): , undeletable"), // - suppressed(0, instanceOf(DirectoryNotEmptyException.class)), // - suppressed(1, instanceOf(IOException.class), message("Simulated failure"))); + cause( // + instanceOf(IOException.class), // + message("Failed to delete temp directory " + tempDir.toAbsolutePath() + ". " + // + "The following paths could not be deleted (see suppressed exceptions for details): , undeletable"), // + suppressed(0, instanceOf(DirectoryNotEmptyException.class)), // + suppressed(1, instanceOf(IOException.class), message("Simulated failure")) // + ) // + ); } @Nested From f4d7fa76cf3950d4aade6c52b13a7a37c62d6b27 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 13 Oct 2023 15:55:26 +0200 Subject: [PATCH 071/142] Declare TrackLogRecords on test method parameters rather than method --- .../jupiter/api/fixtures/TrackLogRecords.java | 2 +- .../engine/MultipleTestableAnnotationsTests.java | 3 +-- .../engine/descriptor/DisplayNameUtilsTests.java | 3 +-- ...onRegistrationViaParametersAndFieldsTests.java | 6 ++---- .../engine/extension/OrderedClassTests.java | 3 +-- .../engine/extension/OrderedMethodTests.java | 15 +++++---------- .../engine/extension/TestWatcherTests.java | 3 +-- .../extension/TimeoutConfigurationTests.java | 6 ++---- .../engine/VintageLauncherIntegrationTests.java | 10 ++++------ .../commons/util/ReflectionUtilsTests.java | 3 +-- .../SameThreadExecutionIntegrationTests.java | 3 +-- .../core/DefaultLauncherEngineFilterTests.java | 6 ++---- .../launcher/core/DefaultLauncherTests.java | 3 +-- 13 files changed, 23 insertions(+), 43 deletions(-) diff --git a/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/fixtures/TrackLogRecords.java b/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/fixtures/TrackLogRecords.java index ef33de69dda6..01619bf454d2 100644 --- a/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/fixtures/TrackLogRecords.java +++ b/junit-jupiter-api/src/testFixtures/java/org/junit/jupiter/api/fixtures/TrackLogRecords.java @@ -41,7 +41,7 @@ * @see LoggerFactory * @see LogRecordListener */ -@Target({ ElementType.TYPE, ElementType.METHOD }) +@Target({ ElementType.TYPE, ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @ExtendWith(TrackLogRecords.Extension.class) public @interface TrackLogRecords { diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/MultipleTestableAnnotationsTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/MultipleTestableAnnotationsTests.java index f8ded8659782..e604a59525ff 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/MultipleTestableAnnotationsTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/MultipleTestableAnnotationsTests.java @@ -29,11 +29,10 @@ * * @since 5.0 */ -@TrackLogRecords class MultipleTestableAnnotationsTests extends AbstractJupiterTestEngineTests { @Test - void testAndRepeatedTest(LogRecordListener listener) { + void testAndRepeatedTest(@TrackLogRecords LogRecordListener listener) { discoverTests(request().selectors(selectClass(TestCase.class)).build()); // @formatter:off diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java index 5a8679e4acd7..cab152e7fe0e 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/DisplayNameUtilsTests.java @@ -47,9 +47,8 @@ void shouldGetDisplayNameFromDisplayNameAnnotation() { } @Test - @TrackLogRecords void shouldGetDisplayNameFromSupplierIfNoDisplayNameAnnotationWithBlankStringPresent( - LogRecordListener listener) { + @TrackLogRecords LogRecordListener listener) { String displayName = DisplayNameUtils.determineDisplayName(BlankDisplayNameTestCase.class, () -> "default-name"); diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java index 5b8a208d0492..aad66de58391 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistrationViaParametersAndFieldsTests.java @@ -138,8 +138,7 @@ void fieldsWithTestInstancePerClass() { } @Test - @TrackLogRecords - void multipleRegistrationsViaField(LogRecordListener listener) { + void multipleRegistrationsViaField(@TrackLogRecords LogRecordListener listener) { assertOneTestSucceeded(MultipleRegistrationsViaFieldTestCase.class); assertThat(getRegisteredLocalExtensions(listener)).containsExactly("LongParameterResolver", "DummyExtension"); } @@ -158,8 +157,7 @@ void duplicateRegistrationViaField() { } @Test - @TrackLogRecords - void registrationOrder(LogRecordListener listener) { + void registrationOrder(@TrackLogRecords LogRecordListener listener) { assertOneTestSucceeded(AllInOneWithTestInstancePerMethodTestCase.class); assertThat(getRegisteredLocalExtensions(listener))// .containsExactly(// diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/OrderedClassTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/OrderedClassTests.java index 09026c6b1362..001fc49053f9 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/OrderedClassTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/OrderedClassTests.java @@ -106,8 +106,7 @@ void orderAnnotationOnNestedTestClassesWithGlobalConfig() { } @Test - @TrackLogRecords - void orderAnnotationOnNestedTestClassesWithLocalConfig(LogRecordListener listener) { + void orderAnnotationOnNestedTestClassesWithLocalConfig(@TrackLogRecords LogRecordListener listener) { executeTests(ClassOrderer.class, selectClass(OuterWithLocalConfig.class))// .assertStatistics(stats -> stats.succeeded(callSequence.size())); diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java index ed86fd2a2448..00c8a113a889 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/OrderedMethodTests.java @@ -179,8 +179,7 @@ void defaultOrderer() { } @Test - @TrackLogRecords - void randomWithBogusSeedRepeatedly(LogRecordListener listener) { + void randomWithBogusSeedRepeatedly(@TrackLogRecords LogRecordListener listener) { var seed = "explode"; var expectedMessagePattern = Pattern.compile( "Failed to convert configuration parameter \\[" + Pattern.quote(Random.RANDOM_SEED_PROPERTY_NAME) @@ -209,8 +208,7 @@ void randomWithBogusSeedRepeatedly(LogRecordListener listener) { } @Test - @TrackLogRecords - void randomWithDifferentSeedConsecutively(LogRecordListener listener) { + void randomWithDifferentSeedConsecutively(@TrackLogRecords LogRecordListener listener) { Set uniqueSequences = new HashSet<>(); for (var i = 0; i < 10; i++) { @@ -240,8 +238,7 @@ void randomWithDifferentSeedConsecutively(LogRecordListener listener) { } @Test - @TrackLogRecords - void randomWithCustomSeed(LogRecordListener listener) { + void randomWithCustomSeed(@TrackLogRecords LogRecordListener listener) { var seed = "42"; var expectedMessage = "Using custom seed for configuration parameter [" + Random.RANDOM_SEED_PROPERTY_NAME + "] with value [" + seed + "]."; @@ -268,8 +265,7 @@ void randomWithCustomSeed(LogRecordListener listener) { } @Test - @TrackLogRecords - void misbehavingMethodOrdererThatAddsElements(LogRecordListener listener) { + void misbehavingMethodOrdererThatAddsElements(@TrackLogRecords LogRecordListener listener) { Class testClass = MisbehavingByAddingTestCase.class; executeTestsInParallel(testClass).assertStatistics(stats -> stats.succeeded(2)); @@ -283,8 +279,7 @@ void misbehavingMethodOrdererThatAddsElements(LogRecordListener listener) { } @Test - @TrackLogRecords - void misbehavingMethodOrdererThatRemovesElements(LogRecordListener listener) { + void misbehavingMethodOrdererThatRemovesElements(@TrackLogRecords LogRecordListener listener) { Class testClass = MisbehavingByRemovingTestCase.class; executeTestsInParallel(testClass).assertStatistics(stats -> stats.succeeded(3)); diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TestWatcherTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TestWatcherTests.java index 6ada22bf2527..bf4e1e2250a0 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TestWatcherTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TestWatcherTests.java @@ -107,8 +107,7 @@ void testWatcherIsNotInvokedForTestFactoryMethods() { } @Test - @TrackLogRecords - void testWatcherExceptionsAreLoggedAndSwallowed(LogRecordListener logRecordListener) { + void testWatcherExceptionsAreLoggedAndSwallowed(@TrackLogRecords LogRecordListener logRecordListener) { assertCommonStatistics(executeTestsForClass(ExceptionThrowingTestWatcherTestCase.class)); // @formatter:off diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutConfigurationTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutConfigurationTests.java index 4886f2718607..996592f951cb 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutConfigurationTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TimeoutConfigurationTests.java @@ -124,8 +124,7 @@ void specificTimeoutsAreUsedIfSet() { } @Test - @TrackLogRecords - void logsInvalidValues(LogRecordListener logRecordListener) { + void logsInvalidValues(@TrackLogRecords LogRecordListener logRecordListener) { when(extensionContext.getConfigurationParameter(DEFAULT_TEST_METHOD_TIMEOUT_PROPERTY_NAME)).thenReturn( Optional.of("invalid")); @@ -143,8 +142,7 @@ void specificThreadModeIsUsed() { } @Test - @TrackLogRecords - void logsInvalidThreadModeValueAndReturnEmpty(LogRecordListener logRecordListener) { + void logsInvalidThreadModeValueAndReturnEmpty(@TrackLogRecords LogRecordListener logRecordListener) { when(extensionContext.getConfigurationParameter(DEFAULT_TIMEOUT_THREAD_MODE_PROPERTY_NAME)).thenReturn( Optional.of("invalid")); diff --git a/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageLauncherIntegrationTests.java b/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageLauncherIntegrationTests.java index cb12669aef13..e6eea6bff78b 100644 --- a/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageLauncherIntegrationTests.java +++ b/junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageLauncherIntegrationTests.java @@ -151,9 +151,8 @@ void removesCompleteClassIfItHasExcludedTag() { .containsExactly("JUnit Vintage"); } - @TrackLogRecords @Test - void executesAllTestsForNotFilterableRunner(LogRecordListener logRecordListener) { + void executesAllTestsForNotFilterableRunner(@TrackLogRecords LogRecordListener logRecordListener) { Class testClass = JUnit4TestCaseWithNotFilterableRunner.class; var request = request() // .selectors(selectClass(testClass)) // @@ -172,9 +171,8 @@ void executesAllTestsForNotFilterableRunner(LogRecordListener logRecordListener) + " does not support filtering and will therefore be run completely."); } - @TrackLogRecords @Test - void executesAllTestsForNotFilterableChildRunnerOfSuite(LogRecordListener logRecordListener) { + void executesAllTestsForNotFilterableChildRunnerOfSuite(@TrackLogRecords LogRecordListener logRecordListener) { Class suiteClass = JUnit4SuiteOfSuiteWithFilterableChildRunner.class; Class testClass = JUnit4TestCaseWithNotFilterableRunner.class; var request = request() // @@ -194,9 +192,9 @@ void executesAllTestsForNotFilterableChildRunnerOfSuite(LogRecordListener logRec + " was not able to satisfy all filter requests."); } - @TrackLogRecords @Test - void executesAllTestsWhenFilterDidNotExcludeTestForJUnit3Suite(LogRecordListener logRecordListener) { + void executesAllTestsWhenFilterDidNotExcludeTestForJUnit3Suite( + @TrackLogRecords LogRecordListener logRecordListener) { Class suiteClass = JUnit3SuiteWithSingleTestCaseWithSingleTestWhichFails.class; Class testClass = PlainJUnit3TestCaseWithSingleTestWhichFails.class; var request = request() // diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index d74b74ce7592..56ed88a8ddcc 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -838,8 +838,7 @@ private void assertNestedCycle(Class start, Class from, Class to) { * @since 1.3 */ @Test - @TrackLogRecords - void findNestedClassesWithInvalidNestedClassFile(LogRecordListener listener) throws Exception { + void findNestedClassesWithInvalidNestedClassFile(@TrackLogRecords LogRecordListener listener) throws Exception { var jarUrl = getClass().getResource("/gh-1436-invalid-nested-class-file.jar"); try (var classLoader = new URLClassLoader(new URL[] { jarUrl })) { diff --git a/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SameThreadExecutionIntegrationTests.java b/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SameThreadExecutionIntegrationTests.java index 9a17de1a825b..838fcacb842e 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SameThreadExecutionIntegrationTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/SameThreadExecutionIntegrationTests.java @@ -32,8 +32,7 @@ class SameThreadExecutionIntegrationTests { * @see gh-1688 */ @Test - @TrackLogRecords - void threadInterruptedByUserCode(LogRecordListener listener) { + void threadInterruptedByUserCode(@TrackLogRecords LogRecordListener listener) { EngineTestKit.engine("junit-jupiter")// .selectors(selectClass(InterruptedThreadTestCase.class))// .execute()// diff --git a/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherEngineFilterTests.java b/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherEngineFilterTests.java index 85732038f6de..34aa62947fad 100644 --- a/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherEngineFilterTests.java +++ b/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherEngineFilterTests.java @@ -148,8 +148,7 @@ void launcherWillExecuteEnginesHonoringBothIncludeAndExcludeEngineFilters() { } @Test - @TrackLogRecords - void launcherThrowsExceptionWhenNoEngineMatchesIncludeEngineFilter(LogRecordListener log) { + void launcherThrowsExceptionWhenNoEngineMatchesIncludeEngineFilter(@TrackLogRecords LogRecordListener log) { var engine = new DemoHierarchicalTestEngine("first"); TestDescriptor test1 = engine.addTest("test1", noOp); LauncherDiscoveryRequest request = request() // @@ -169,8 +168,7 @@ void launcherThrowsExceptionWhenNoEngineMatchesIncludeEngineFilter(LogRecordList } @Test - @TrackLogRecords - void launcherWillLogWarningWhenAllEnginesWereExcluded(LogRecordListener log) { + void launcherWillLogWarningWhenAllEnginesWereExcluded(@TrackLogRecords LogRecordListener log) { var engine = new DemoHierarchicalTestEngine("first"); TestDescriptor test = engine.addTest("test1", noOp); diff --git a/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherTests.java b/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherTests.java index f5b777b4b71d..2549fbc4c5e8 100644 --- a/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherTests.java +++ b/platform-tests/src/test/java/org/junit/platform/launcher/core/DefaultLauncherTests.java @@ -597,8 +597,7 @@ void testPlanThrowsExceptionWhenModified() { } @Test - @TrackLogRecords - void thirdPartyEngineUsingReservedEngineIdPrefixEmitsWarning(LogRecordListener listener) { + void thirdPartyEngineUsingReservedEngineIdPrefixEmitsWarning(@TrackLogRecords LogRecordListener listener) { var id = "junit-using-reserved-prefix"; var launcher = createLauncher(new TestEngineStub(id)); launcher.discover(request().build()); From 766561f5884600ee91c1845c647c8ce21c7c38da Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 15 Oct 2023 19:15:40 +0200 Subject: [PATCH 072/142] Use consistent wording in Javadoc for @[Enabled|Disabled] annotations --- .../org/junit/jupiter/api/condition/DisabledForJreRange.java | 4 ++-- .../main/java/org/junit/jupiter/api/condition/DisabledIf.java | 4 ++-- .../junit/jupiter/api/condition/DisabledInNativeImage.java | 2 +- .../java/org/junit/jupiter/api/condition/DisabledOnJre.java | 4 ++-- .../main/java/org/junit/jupiter/api/condition/EnabledIf.java | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java index 47d5af673cd2..1b175ed34d91 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java @@ -22,8 +22,8 @@ import org.junit.jupiter.api.extension.ExtendWith; /** - * {@code @DisabledForJreRange} is used to signal that the annotated test class or - * test method is only disabled for a specific range of Java Runtime + * {@code @DisabledForJreRange} is used to signal that the annotated test class + * or test method is disabled for a specific range of Java Runtime * Environment (JRE) versions from {@link #min} to {@link #max}. * *

When applied at the class level, all test methods within that class will diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java index 88e3f8e329fd..1d3f119662da 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledIf.java @@ -23,8 +23,8 @@ /** * {@code @DisabledIf} is used to signal that the annotated test class or test - * method is disabled only if the provided - * {@linkplain #value() condition} evaluates to {@code true}. + * method is disabled if the provided {@linkplain #value() condition} + * evaluates to {@code true}. * *

When applied at the class level, all test methods within that class will * be disabled on the same condition. diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java index d996b71705d8..06ea015ebf88 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledInNativeImage.java @@ -22,7 +22,7 @@ /** * {@code @DisabledInNativeImage} is used to signal that the annotated test class - * or test method is only disabled when executing within a GraalVM native + * or test method is disabled when executing within a GraalVM native * image. * *

When applied at the class level, all test methods within that class will diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java index e707c0f74a99..5d66386056cd 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java @@ -23,8 +23,8 @@ /** * {@code @DisabledOnJre} is used to signal that the annotated test class or - * test method is disabled on one or more specified Java - * Runtime Environment (JRE) {@linkplain #value versions}. + * test method is disabled on one or more specified Java Runtime + * Environment (JRE) {@linkplain #value versions}. * *

When applied at the class level, all test methods within that class * will be disabled on the same specified JRE versions. diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java index 2087c1ca1de6..f28b1f8d2a1a 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledIf.java @@ -23,8 +23,8 @@ /** * {@code @EnabledIf} is used to signal that the annotated test class or test - * method is enabled only if the provided - * {@linkplain #value() condition} evaluates to {@code true}. + * method is only enabled if the provided {@linkplain #value() condition} + * evaluates to {@code true}. * *

When applied at the class level, all test methods within that class will * be enabled on the same condition. From 2c9a318984a0bd8007bc28150849bb653e2b6c86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 05:27:21 +0000 Subject: [PATCH 073/142] Bump log4j from 2.20.0 to 2.21.0 Bumps `log4j` from 2.20.0 to 2.21.0. Updates `org.apache.logging.log4j:log4j-core` from 2.20.0 to 2.21.0 Updates `org.apache.logging.log4j:log4j-jul` from 2.20.0 to 2.21.0 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.apache.logging.log4j:log4j-jul dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0eebc69fe3e9..da3dddf4694d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ junit4 = "4.13.2" junit4Osgi = "4.13.2_1" junit4Min = "4.12" ktlint = "0.48.2" -log4j = "2.20.0" +log4j = "2.21.0" opentest4j = "1.3.0" openTestReporting = "0.1.0-M1" surefire = "3.1.2" From 54836624ce650b8045024540c48a60ed3c41243f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Oct 2023 05:27:34 +0000 Subject: [PATCH 074/142] Bump org.ajoberstar.git-publish from 4.2.0 to 4.2.1 Bumps [org.ajoberstar.git-publish](https://github.com/ajoberstar/gradle-git-publish) from 4.2.0 to 4.2.1. - [Release notes](https://github.com/ajoberstar/gradle-git-publish/releases) - [Commits](https://github.com/ajoberstar/gradle-git-publish/compare/4.2.0...4.2.1) --- updated-dependencies: - dependency-name: org.ajoberstar.git-publish dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index da3dddf4694d..7c4b581e4017 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -79,7 +79,7 @@ xmlunit = ["xmlunit-assertj", "xmlunit-placeholders"] asciidoctorConvert = { id = "org.asciidoctor.jvm.convert", version.ref = "asciidoctor-plugins" } asciidoctorPdf = { id = "org.asciidoctor.jvm.pdf", version.ref = "asciidoctor-plugins" } buildParameters = { id = "org.gradlex.build-parameters", version = "1.4.3" } -gitPublish = { id = "org.ajoberstar.git-publish", version = "4.2.0" } +gitPublish = { id = "org.ajoberstar.git-publish", version = "4.2.1" } jmh = { id = "me.champeau.jmh", version = "0.7.1" } nohttp = { id = "io.spring.nohttp", version = "0.0.11" } nexusPublish = { id = "io.github.gradle-nexus.publish-plugin", version = "2.0.0-rc-1" } From 429815fec80f0e6e1887119e4a5eb6bd476e9279 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 27 Oct 2023 14:25:33 +0200 Subject: [PATCH 075/142] Generate component diagram with plantuml separately Since the file is missing intermittently from the output of Asciidoctor it's now generated separately in a standalone `plantuml` task. --- documentation/documentation.gradle.kts | 18 ++-- .../docs/asciidoc/user-guide/appendix.adoc | 98 +------------------ .../src/plantuml/component-diagram.puml | 98 +++++++++++++++++++ gradle/libs.versions.toml | 1 + 4 files changed, 111 insertions(+), 104 deletions(-) create mode 100644 documentation/src/plantuml/component-diagram.puml diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index da73ae62b0e7..fbe0413e3b54 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -11,6 +11,7 @@ plugins { alias(libs.plugins.asciidoctorConvert) alias(libs.plugins.asciidoctorPdf) alias(libs.plugins.gitPublish) + alias(libs.plugins.plantuml) id("junitbuild.build-parameters") id("junitbuild.kotlin-library-conventions") id("junitbuild.testing-conventions") @@ -207,6 +208,13 @@ tasks { outputFile = standaloneConsoleLauncherShadowedArtifactsFile } + plantUml { + fileFormat = "SVG" + outputs.cacheIf { true } + } + + val componentDiagram = plantUml.flatMap { it.outputDirectory.file("component-diagram.svg") } + withType().configureEach { inputs.files( generateConsoleLauncherOptions, @@ -215,7 +223,8 @@ tasks { generateConsoleLauncherEnginesOptions, generateExperimentalApisTable, generateDeprecatedApisTable, - generateStandaloneConsoleLauncherShadowedArtifactsFile + generateStandaloneConsoleLauncherShadowedArtifactsFile, + componentDiagram ) resources { @@ -248,6 +257,7 @@ tasks { "experimentalApisTableFile" to experimentalApisTableFile.get(), "deprecatedApisTableFile" to deprecatedApisTableFile.get(), "standaloneConsoleLauncherShadowedArtifactsFile" to standaloneConsoleLauncherShadowedArtifactsFile.get(), + "componentDiagramFile" to componentDiagram.get(), "outdir" to outputDir.absolutePath, "source-highlighter" to "rouge", "rouge-style" to "junit", @@ -297,12 +307,6 @@ tasks { "userGuidePdfFileName" to userGuidePdfFileName, "releaseNotesUrl" to "../release-notes/index.html#release-notes" )) - doLast { - val componentDiagramSvg = outputDirProperty.file("user-guide/images/component-diagram.svg").get().asFile - require(componentDiagramSvg.exists()) { - "Component diagram was not generated at $componentDiagramSvg" - } - } } asciidoctorPdf { diff --git a/documentation/src/docs/asciidoc/user-guide/appendix.adoc b/documentation/src/docs/asciidoc/user-guide/appendix.adoc index a5d8290b5d75..06a72fb4880b 100644 --- a/documentation/src/docs/asciidoc/user-guide/appendix.adoc +++ b/documentation/src/docs/asciidoc/user-guide/appendix.adoc @@ -133,100 +133,4 @@ following _OpenTest4J_ JAR. [[dependency-diagram]] === Dependency Diagram -[plantuml, component-diagram, svg] ----- -skinparam { - defaultFontName Open Sans -} - -package org.junit.jupiter { - [junit-jupiter] as jupiter - [junit-jupiter-api] as jupiter_api - [junit-jupiter-engine] as jupiter_engine - [junit-jupiter-params] as jupiter_params - [junit-jupiter-migrationsupport] as jupiter_migration_support -} - -package org.junit.vintage { - [junit-vintage-engine] as vintage_engine -} - -package org.junit.platform { - [junit-platform-commons] as commons - [junit-platform-console] as console - [junit-platform-engine] as engine - [junit-platform-jfr] as jfr - [junit-platform-launcher] as launcher - [junit-platform-reporting] as reporting - [junit-platform-runner] as runner - [junit-platform-suite] as suite - [junit-platform-suite-api] as suite_api - [junit-platform-suite-commons] as suite_commons - [junit-platform-suite-engine] as suite_engine - [junit-platform-testkit] as testkit -} - -package "JUnit 4" { - [junit:junit] as junit4 -} - -package org.opentest4j { - [opentest4j] -} - -package org.apiguardian { - [apiguardian-api] as apiguardian - note bottom of apiguardian #white - All artifacts except - opentest4j and junit:junit - have a dependency on this - artifact. The edges have - been omitted from this - diagram for the sake of - readability. - endnote -} - -jupiter ..> jupiter_api -jupiter ..> jupiter_params -jupiter ..> jupiter_engine - -jupiter_api ....> opentest4j -jupiter_api ...> commons - -jupiter_engine ...> engine -jupiter_engine ..> jupiter_api - -jupiter_params ..> jupiter_api -jupiter_migration_support ..> jupiter_api -jupiter_migration_support ...> junit4 - -console ..> launcher -console ..> reporting - -launcher ..> engine - -jfr ..> launcher - -engine ....> opentest4j -engine ..> commons - -reporting ..> launcher - -runner ..> suite_commons -runner ...> junit4 - -suite ..> suite_api -suite ..> suite_engine - -suite_engine ..> suite_commons - -suite_commons ..> launcher -suite_commons ..> suite_api - -testkit ....> opentest4j -testkit ..> launcher - -vintage_engine ...> engine -vintage_engine ..> junit4 ----- +image::{componentDiagramFile}[] diff --git a/documentation/src/plantuml/component-diagram.puml b/documentation/src/plantuml/component-diagram.puml new file mode 100644 index 000000000000..4874f5e1abb8 --- /dev/null +++ b/documentation/src/plantuml/component-diagram.puml @@ -0,0 +1,98 @@ +@startuml + +skinparam { + defaultFontName sans-serif +} + +package org.junit.jupiter { + [junit-jupiter] as jupiter + [junit-jupiter-api] as jupiter_api + [junit-jupiter-engine] as jupiter_engine + [junit-jupiter-params] as jupiter_params + [junit-jupiter-migrationsupport] as jupiter_migration_support +} + +package org.junit.vintage { + [junit-vintage-engine] as vintage_engine +} + +package org.junit.platform { + [junit-platform-commons] as commons + [junit-platform-console] as console + [junit-platform-engine] as engine + [junit-platform-jfr] as jfr + [junit-platform-launcher] as launcher + [junit-platform-reporting] as reporting + [junit-platform-runner] as runner + [junit-platform-suite] as suite + [junit-platform-suite-api] as suite_api + [junit-platform-suite-commons] as suite_commons + [junit-platform-suite-engine] as suite_engine + [junit-platform-testkit] as testkit +} + +package "JUnit 4" { + [junit:junit] as junit4 +} + +package org.opentest4j { + [opentest4j] +} + +package org.apiguardian { + [apiguardian-api] as apiguardian + note bottom of apiguardian #white + All artifacts except + opentest4j and junit:junit + have a dependency on this + artifact. The edges have + been omitted from this + diagram for the sake of + readability. + endnote +} + +jupiter ..> jupiter_api +jupiter ..> jupiter_params +jupiter ..> jupiter_engine + +jupiter_api ....> opentest4j +jupiter_api ...> commons + +jupiter_engine ...> engine +jupiter_engine ..> jupiter_api + +jupiter_params ..> jupiter_api +jupiter_migration_support ..> jupiter_api +jupiter_migration_support ...> junit4 + +console ..> launcher +console ..> reporting + +launcher ..> engine + +jfr ..> launcher + +engine ....> opentest4j +engine ..> commons + +reporting ..> launcher + +runner ..> suite_commons +runner ...> junit4 + +suite ..> suite_api +suite ..> suite_engine + +suite_engine ..> suite_commons + +suite_commons ..> launcher +suite_commons ..> suite_api + +testkit ....> opentest4j +testkit ..> launcher + +vintage_engine ...> engine +vintage_engine ..> junit4 + +@enduml diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c4b581e4017..46dd9d6897c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -83,4 +83,5 @@ gitPublish = { id = "org.ajoberstar.git-publish", version = "4.2.1" } jmh = { id = "me.champeau.jmh", version = "0.7.1" } nohttp = { id = "io.spring.nohttp", version = "0.0.11" } nexusPublish = { id = "io.github.gradle-nexus.publish-plugin", version = "2.0.0-rc-1" } +plantuml = { id = "io.freefair.plantuml", version = "8.4" } versions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersionsPlugin" } From 544bc85d83e50349009a3d8a1424d32753926c9a Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 27 Oct 2023 14:32:47 +0200 Subject: [PATCH 076/142] Remove dependency on asciidoctorj-diagram --- documentation/documentation.gradle.kts | 1 - gradle/libs.versions.toml | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index fbe0413e3b54..ea2755cba333 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -64,7 +64,6 @@ dependencies { asciidoctorj { modules { - diagram.version(libs.versions.asciidoctorj.diagram) pdf.version(libs.versions.asciidoctorj.pdf) } requires(file("src/docs/asciidoc/resources/themes/rouge_junit.rb")) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 46dd9d6897c0..c4437ecee64b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,6 @@ [versions] ant = "1.10.14" apiguardian = "1.1.2" -asciidoctorj-diagram = "2.2.9" asciidoctorj-pdf = "2.3.9" asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gradle.kts can be removed when upgrading assertj = "3.24.2" @@ -66,8 +65,7 @@ xmlunit-assertj = { module = "org.xmlunit:xmlunit-assertj3", version.ref = "xmlu xmlunit-placeholders = { module = "org.xmlunit:xmlunit-placeholders", version.ref = "xmlunit" } testingAnnotations = { module = "com.gradle:gradle-enterprise-testing-annotations", version = "1.1.2" } -# These are only declared here so Dependabot knows when to update the referenced versions -asciidoctorj-diagram = { module = "org.asciidoctor:asciidoctorj-diagram", version.ref = "asciidoctorj-diagram" } +# Only declared here so Dependabot knows when to update the referenced versions asciidoctorj-pdf = { module = "org.asciidoctor:asciidoctorj-pdf", version.ref = "asciidoctorj-pdf" } [bundles] From 6bc83bd9a12750ace4745af3ef0732da87bd6f10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Oct 2023 12:34:08 +0000 Subject: [PATCH 077/142] Bump com.gradle:gradle-enterprise-gradle-plugin from 3.15 to 3.15.1 Bumps com.gradle:gradle-enterprise-gradle-plugin from 3.15 to 3.15.1. --- updated-dependencies: - dependency-name: com.gradle:gradle-enterprise-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c4437ecee64b..e651dba04c19 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,7 +33,7 @@ classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.162" } commons-io = { module = "commons-io:commons-io", version = "2.14.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.3" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } -gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15" } +gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15.1" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.22.0" } From 5f26cbaef67a48f89e267ab03b75883b64218cc4 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 30 Oct 2023 15:27:23 +0100 Subject: [PATCH 078/142] Remove used Logger See #3422 --- .../engine/execution/JupiterEngineExecutionContext.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java index 81c38308563d..30f461189637 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/execution/JupiterEngineExecutionContext.java @@ -17,8 +17,6 @@ import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.extension.MutableExtensionRegistry; import org.junit.platform.commons.JUnitException; -import org.junit.platform.commons.logging.Logger; -import org.junit.platform.commons.logging.LoggerFactory; import org.junit.platform.engine.EngineExecutionListener; import org.junit.platform.engine.support.hierarchical.EngineExecutionContext; import org.junit.platform.engine.support.hierarchical.ThrowableCollector; @@ -29,8 +27,6 @@ @API(status = INTERNAL, since = "5.0") public class JupiterEngineExecutionContext implements EngineExecutionContext { - private static final Logger logger = LoggerFactory.getLogger(JupiterEngineExecutionContext.class); - private final State state; // The following is not "cloneable" State. From 8dd95af21c324de4ad53f2d8ab7be32964d24c76 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 30 Oct 2023 18:00:01 +0100 Subject: [PATCH 079/142] Prepare release notes for 5.10.1 --- .../release-notes/release-notes-5.10.1.adoc | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc index 10d42587bbb9..cb575e6f4dc3 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -3,7 +3,7 @@ *Date of Release:* ❓ -*Scope:* ❓ +*Scope:* minor bug fixes and improvements since 5.10.0. For a complete list of all _closed_ issues and pull requests for this release, consult the link:{junit5-repo}+/milestone/72?closed=1+[5.10.1] milestone page in the @@ -17,14 +17,6 @@ JUnit repository on GitHub. * ❓ -==== Deprecations and Breaking Changes - -* ❓ - -==== New Features and Improvements - -* ❓ - [[release-notes-5.10.1-junit-jupiter]] === JUnit Jupiter @@ -35,10 +27,6 @@ JUnit repository on GitHub. <<../user-guide/index.adoc#extensions-RandomNumberExtension, User Guide>> has been updated to properly support `Integer` types as well as non-static field injection. -==== Deprecations and Breaking Changes - -* ❓ - ==== New Features and Improvements * Improved Javadoc for `Assertions.assertTimeoutPreemptively` regarding thread interrupt. @@ -52,11 +40,3 @@ JUnit repository on GitHub. ==== Bug Fixes * Fixed reporting for JUnit 3 test classes that use JUnit 4's `@Ignored` annotation. - -==== Deprecations and Breaking Changes - -* ❓ - -==== New Features and Improvements - -* ❓ From 64ed21a2c956bc872abede16cc42ddaa5c1d15c7 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 9 Oct 2023 15:49:51 +0200 Subject: [PATCH 080/142] Apply method predicate before searching type hierarchy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this commit, findMethods() and streamMethods() in ReflectionSupport as well as findAnnotatedMethods() in AnnotationSupport first searched for all methods in the type hierarchy and then applied the user-supplied predicate (or "is annotated?" predicate) afterwards. This resulted in methods in subclasses incorrectly "shadowing" package-private methods in superclasses (in a different package) even if the predicate would otherwise exclude the method in such a subclass. For example, given a superclass that declares a package-private static @⁠BeforeAll "before()" method and a subclass (in a different package) that declares a @⁠BeforeEach "before()" method, when JUnit Jupiter looked up @⁠BeforeAll methods for the subclass, the @⁠BeforeAll "before()" method in the superclass was not found because the @⁠BeforeEach "before()" method shadowed it based solely on the method signature, ignoring the type of annotation sought. To address that, this commit modifies the internal search algorithms in ReflectionUtils so that method predicates are applied while searching the hierarchy for methods. Closes #3498 Closes #3500 --- .../release-notes/release-notes-5.10.1.adoc | 10 +++++- .../commons/util/ReflectionUtils.java | 32 ++++++++++--------- .../commons/util/AnnotationUtilsTests.java | 27 ++++++++++++++++ .../commons/util/ReflectionUtilsTests.java | 24 ++++++++++++++ ...sWithStaticPackagePrivateBeforeMethod.java | 25 +++++++++++++++ ...thNonStaticPackagePrivateBeforeMethod.java | 26 +++++++++++++++ 6 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateBeforeMethod.java create mode 100644 platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateBeforeMethod.java diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc index cb575e6f4dc3..abd61752cc23 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -15,7 +15,10 @@ JUnit repository on GitHub. ==== Bug Fixes -* ❓ +* Method predicates are now applied while searching the type hierarchy. This fixes bugs + in `findMethods(...)` and `streamMethods(...)` in `ReflectionSupport` as well as + `findAnnotatedMethods(...)` in `AnnotationSupport`. + - See link:https://github.com/junit-team/junit5/issues/3498[issue 3498] for details. [[release-notes-5.10.1-junit-jupiter]] @@ -23,6 +26,11 @@ JUnit repository on GitHub. ==== Bug Fixes +* A package-private class-level lifecycle method annotated with `@BeforeAll` or + `@AfterAll` is no longer _shadowed_ by a method-level lifecycle method annotated with + `@BeforeEach` or `@AfterEach` when the method-level lifecycle method resides in a + different package and has the same name as the class-level lifecycle method. + - See link:https://github.com/junit-team/junit5/issues/3498[issue 3498] for details. * The `RandomNumberExtension` example in the <<../user-guide/index.adoc#extensions-RandomNumberExtension, User Guide>> has been updated to properly support `Integer` types as well as non-static field injection. diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 816b7fadd104..927b97451e0a 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -1489,29 +1489,27 @@ public static Stream streamMethods(Class clazz, Predicate pre Preconditions.notNull(predicate, "Predicate must not be null"); Preconditions.notNull(traversalMode, "HierarchyTraversalMode must not be null"); - // @formatter:off - return findAllMethodsInHierarchy(clazz, traversalMode).stream() - .filter(predicate) - .distinct(); - // @formatter:on + return findAllMethodsInHierarchy(clazz, predicate, traversalMode).stream().distinct(); } /** * Find all non-synthetic methods in the superclass and interface hierarchy, - * excluding Object. + * excluding Object, that match the specified {@code predicate}. */ - private static List findAllMethodsInHierarchy(Class clazz, HierarchyTraversalMode traversalMode) { + private static List findAllMethodsInHierarchy(Class clazz, Predicate predicate, + HierarchyTraversalMode traversalMode) { + Preconditions.notNull(clazz, "Class must not be null"); Preconditions.notNull(traversalMode, "HierarchyTraversalMode must not be null"); // @formatter:off List localMethods = getDeclaredMethods(clazz, traversalMode).stream() - .filter(method -> !method.isSynthetic()) + .filter(predicate.and(method -> !method.isSynthetic())) .collect(toList()); - List superclassMethods = getSuperclassMethods(clazz, traversalMode).stream() + List superclassMethods = getSuperclassMethods(clazz, predicate, traversalMode).stream() .filter(method -> !isMethodShadowedByLocalMethods(method, localMethods)) .collect(toList()); - List interfaceMethods = getInterfaceMethods(clazz, traversalMode).stream() + List interfaceMethods = getInterfaceMethods(clazz, predicate, traversalMode).stream() .filter(method -> !isMethodShadowedByLocalMethods(method, localMethods)) .collect(toList()); // @formatter:on @@ -1647,16 +1645,18 @@ private static int defaultMethodSorter(Method method1, Method method2) { return comparison; } - private static List getInterfaceMethods(Class clazz, HierarchyTraversalMode traversalMode) { + private static List getInterfaceMethods(Class clazz, Predicate predicate, + HierarchyTraversalMode traversalMode) { + List allInterfaceMethods = new ArrayList<>(); for (Class ifc : clazz.getInterfaces()) { // @formatter:off List localInterfaceMethods = getMethods(ifc).stream() - .filter(m -> !isAbstract(m)) + .filter(predicate.and(method -> !isAbstract(method))) .collect(toList()); - List superinterfaceMethods = getInterfaceMethods(ifc, traversalMode).stream() + List superinterfaceMethods = getInterfaceMethods(ifc, predicate, traversalMode).stream() .filter(method -> !isMethodShadowedByLocalMethods(method, localInterfaceMethods)) .collect(toList()); // @formatter:on @@ -1706,12 +1706,14 @@ private static boolean isFieldShadowedByLocalFields(Field field, List loc return localFields.stream().anyMatch(local -> local.getName().equals(field.getName())); } - private static List getSuperclassMethods(Class clazz, HierarchyTraversalMode traversalMode) { + private static List getSuperclassMethods(Class clazz, Predicate predicate, + HierarchyTraversalMode traversalMode) { + Class superclass = clazz.getSuperclass(); if (!isSearchable(superclass)) { return Collections.emptyList(); } - return findAllMethodsInHierarchy(superclass, traversalMode); + return findAllMethodsInHierarchy(superclass, predicate, traversalMode); } private static boolean isMethodShadowedByLocalMethods(Method method, List localMethods) { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java index 478491014be1..f26f5ab755d3 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java @@ -36,13 +36,18 @@ import java.lang.annotation.Target; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.List; import java.util.Optional; import java.util.function.Predicate; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateBeforeMethod; +import org.junit.platform.commons.util.pkg1.subpkg.SubclassWithNonStaticPackagePrivateBeforeMethod; /** * Unit tests for {@link AnnotationUtils}. @@ -380,6 +385,28 @@ void findAnnotatedMethodsForAnnotationUsedInClassAndSuperclassHierarchyDown() th assertThat(methods.subList(1, 3)).containsOnly(method1, method3); } + /** + * @see https://github.com/junit-team/junit5/issues/3498 + */ + @Test + void findAnnotatedMethodsAppliesPredicateBeforeSearchingTypeHierarchy() throws Exception { + final String BEFORE = "before"; + Class superclass = SuperclassWithStaticPackagePrivateBeforeMethod.class; + Method beforeAllMethod = superclass.getDeclaredMethod(BEFORE); + Class subclass = SubclassWithNonStaticPackagePrivateBeforeMethod.class; + Method beforeEachMethod = subclass.getDeclaredMethod(BEFORE); + + // Prerequisite + var methods = findAnnotatedMethods(superclass, BeforeAll.class, TOP_DOWN); + assertThat(methods).containsExactly(beforeAllMethod); + + // Actual use cases for this test + methods = findAnnotatedMethods(subclass, BeforeAll.class, TOP_DOWN); + assertThat(methods).containsExactly(beforeAllMethod); + methods = findAnnotatedMethods(subclass, BeforeEach.class, TOP_DOWN); + assertThat(methods).containsExactly(beforeEachMethod); + } + @Test void findAnnotatedMethodsForAnnotationUsedInInterface() throws Exception { var interfaceMethod = InterfaceWithAnnotatedDefaultMethod.class.getDeclaredMethod("interfaceMethod"); diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 56ed88a8ddcc..30a403fe00c6 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -72,6 +72,8 @@ import org.junit.platform.commons.util.ReflectionUtilsTests.OuterClass.StaticNestedSiblingClass; import org.junit.platform.commons.util.ReflectionUtilsTests.OuterClassImplementingInterface.InnerClassImplementingInterface; import org.junit.platform.commons.util.classes.CustomType; +import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateBeforeMethod; +import org.junit.platform.commons.util.pkg1.subpkg.SubclassWithNonStaticPackagePrivateBeforeMethod; /** * Unit tests for {@link ReflectionUtils}. @@ -1344,6 +1346,28 @@ void findMethodsIgnoresBridgeMethods() throws Exception { assertEquals(0, methods.stream().filter(Method::isBridge).count()); } + /** + * @see https://github.com/junit-team/junit5/issues/3498 + */ + @Test + void findMethodsAppliesPredicateBeforeSearchingTypeHierarchy() throws Exception { + final String BEFORE = "before"; + Class superclass = SuperclassWithStaticPackagePrivateBeforeMethod.class; + Method staticMethod = superclass.getDeclaredMethod(BEFORE); + Class subclass = SubclassWithNonStaticPackagePrivateBeforeMethod.class; + Method nonStaticMethod = subclass.getDeclaredMethod(BEFORE); + + // Prerequisite + var methods = findMethods(superclass, ReflectionUtils::isStatic); + assertThat(methods).containsExactly(staticMethod); + + // Actual use cases for this test + methods = findMethods(subclass, ReflectionUtils::isStatic); + assertThat(methods).containsExactly(staticMethod); + methods = findMethods(subclass, ReflectionUtils::isNotStatic); + assertThat(methods).containsExactly(nonStaticMethod); + } + @Test void isGeneric() { for (var method : Generic.class.getMethods()) { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateBeforeMethod.java b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateBeforeMethod.java new file mode 100644 index 000000000000..2895f2b4980d --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateBeforeMethod.java @@ -0,0 +1,25 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util.pkg1; + +import org.junit.jupiter.api.BeforeAll; + +/** + * @see https://github.com/junit-team/junit5/issues/3498 + */ +public class SuperclassWithStaticPackagePrivateBeforeMethod { + + @BeforeAll + static void before() { + // no-op + } + +} diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateBeforeMethod.java b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateBeforeMethod.java new file mode 100644 index 000000000000..c7c6d1e0ac22 --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateBeforeMethod.java @@ -0,0 +1,26 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util.pkg1.subpkg; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateBeforeMethod; + +/** + * @see https://github.com/junit-team/junit5/issues/3498 + */ +public class SubclassWithNonStaticPackagePrivateBeforeMethod extends SuperclassWithStaticPackagePrivateBeforeMethod { + + @BeforeEach + void before() { + // no-op + } + +} From cae8c132a27f8d3801094817f3397dab0d808662 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 28 Oct 2023 15:45:28 +0000 Subject: [PATCH 081/142] Bump io.github.classgraph:classgraph from 4.8.162 to 4.8.163 Bumps [io.github.classgraph:classgraph](https://github.com/classgraph/classgraph) from 4.8.162 to 4.8.163. - [Release notes](https://github.com/classgraph/classgraph/releases) - [Commits](https://github.com/classgraph/classgraph/compare/classgraph-4.8.162...classgraph-4.8.163) --- updated-dependencies: - dependency-name: io.github.classgraph:classgraph dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e651dba04c19..6be8c210d3cc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } -classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.162" } +classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.163" } commons-io = { module = "commons-io:commons-io", version = "2.14.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.3" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } From b1d7e22cfd1e8e83ef5bd9aeb77a5ca2f261befa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 05:52:22 +0000 Subject: [PATCH 082/142] Bump org.apache.maven.plugins:maven-surefire-plugin from 3.1.2 to 3.2.1 Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.1.2 to 3.2.1. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.2...surefire-3.2.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6be8c210d3cc..109a668cf58d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,7 @@ ktlint = "0.48.2" log4j = "2.21.0" opentest4j = "1.3.0" openTestReporting = "0.1.0-M1" -surefire = "3.1.2" +surefire = "3.2.1" xmlunit = "2.9.1" [libraries] From 6916f65e0a3dc8fb53dc0691881ea6e2ac30d9ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 05:52:30 +0000 Subject: [PATCH 083/142] Bump log4j from 2.21.0 to 2.21.1 Bumps `log4j` from 2.21.0 to 2.21.1. Updates `org.apache.logging.log4j:log4j-core` from 2.21.0 to 2.21.1 Updates `org.apache.logging.log4j:log4j-jul` from 2.21.0 to 2.21.1 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: org.apache.logging.log4j:log4j-jul dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 109a668cf58d..c76ea1d96dff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ junit4 = "4.13.2" junit4Osgi = "4.13.2_1" junit4Min = "4.12" ktlint = "0.48.2" -log4j = "2.21.0" +log4j = "2.21.1" opentest4j = "1.3.0" openTestReporting = "0.1.0-M1" surefire = "3.2.1" From e9102be2a266d3d4c2962617542e534c7a521247 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 31 Oct 2023 13:52:15 +0100 Subject: [PATCH 084/142] Take into account failures of children for ON_SUCCESS cleanup mode Prior to this commit, the `ON_SUCCESS` cleanup mode of `@TempDir` would only take into account failures of the level the `@TempDir` was declared on but not of its children. Fixes #3510. --- .../release-notes/release-notes-5.10.1.adoc | 2 + .../engine/extension/TempDirectory.java | 17 +++++- .../extension/TempDirectoryCleanupTests.java | 59 +++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc index abd61752cc23..65c3aa6055b4 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -34,6 +34,8 @@ JUnit repository on GitHub. * The `RandomNumberExtension` example in the <<../user-guide/index.adoc#extensions-RandomNumberExtension, User Guide>> has been updated to properly support `Integer` types as well as non-static field injection. +* The `ON_SUCCESS` cleanup mode of `@TempDir` now takes into account failures of test + methods and nested tests when it's declared on the class level, e.g. as a static field. ==== New Features and Improvements diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java index fe76498bd4ae..de2398b94f3e 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java @@ -79,6 +79,8 @@ class TempDirectory implements BeforeAllCallback, BeforeEachCallback, ParameterR static final Namespace NAMESPACE = Namespace.create(TempDirectory.class); private static final String KEY = "temp.dir"; + private static final String FAILURE_TRACKER = "failure.tracker"; + private static final String CHILD_FAILED = "child.failed"; // for testing purposes static final String FILE_OPERATIONS_KEY = "file.operations"; @@ -96,6 +98,7 @@ public TempDirectory(JupiterConfiguration configuration) { */ @Override public void beforeAll(ExtensionContext context) { + installFailureTracker(context); injectStaticFields(context, context.getRequiredTestClass()); } @@ -106,10 +109,16 @@ public void beforeAll(ExtensionContext context) { */ @Override public void beforeEach(ExtensionContext context) { + installFailureTracker(context); context.getRequiredTestInstances().getAllInstances() // .forEach(instance -> injectInstanceFields(context, instance)); } + private static void installFailureTracker(ExtensionContext context) { + context.getStore(NAMESPACE).put(FAILURE_TRACKER, (CloseableResource) () -> context.getParent() // + .ifPresent(it -> it.getStore(NAMESPACE).put(CHILD_FAILED, selfOrChildFailed(context)))); + } + private void injectStaticFields(ExtensionContext context, Class testClass) { injectFields(context, null, testClass, ReflectionUtils::isStatic); } @@ -257,6 +266,11 @@ static CloseablePath createTempDir(TempDirFactory factory, CleanupMode cleanupMo } } + private static boolean selfOrChildFailed(ExtensionContext context) { + return context.getExecutionException().isPresent() // + || Boolean.TRUE.equals(context.getStore(NAMESPACE).get(CHILD_FAILED)); + } + static class CloseablePath implements CloseableResource { private static final Logger logger = LoggerFactory.getLogger(CloseablePath.class); @@ -281,8 +295,7 @@ Path get() { @Override public void close() throws IOException { try { - if (cleanupMode == NEVER - || (cleanupMode == ON_SUCCESS && extensionContext.getExecutionException().isPresent())) { + if (cleanupMode == NEVER || (cleanupMode == ON_SUCCESS && selfOrChildFailed(extensionContext))) { logger.info(() -> "Skipping cleanup of temp dir " + dir + " due to cleanup mode configuration."); return; } diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java index ddaaa214f786..c3dfb781f8c8 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java @@ -16,6 +16,7 @@ import static org.junit.jupiter.api.io.CleanupMode.ALWAYS; import static org.junit.jupiter.api.io.CleanupMode.NEVER; import static org.junit.jupiter.api.io.CleanupMode.ON_SUCCESS; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; @@ -141,6 +142,36 @@ void cleanupModeOnSuccessFailingField() { assertThat(onSuccessFailingFieldDir).exists(); } + /** + * Ensure that ON_SUCCESS cleanup modes are obeyed for static fields when tests are failing. + *

+ * Expect the TempDir not to be cleaned up. + */ + @Test + void cleanupModeOnSuccessFailingStaticField() { + LauncherDiscoveryRequest request = request()// + .selectors(selectClass(OnSuccessFailingStaticFieldCase.class))// + .build(); + executeTests(request); + + assertThat(onSuccessFailingFieldDir).exists(); + } + + /** + * Ensure that ON_SUCCESS cleanup modes are obeyed for static fields when nested tests are failing. + *

+ * Expect the TempDir not to be cleaned up. + */ + @Test + void cleanupModeOnSuccessFailingStaticFieldWithNesting() { + LauncherDiscoveryRequest request = request()// + .selectors(selectClass(OnSuccessFailingStaticFieldWithNestingCase.class))// + .build(); + executeTests(request); + + assertThat(onSuccessFailingFieldDir).exists(); + } + @AfterAll static void afterAll() throws IOException { deleteIfExists(defaultFieldDir); @@ -208,6 +239,34 @@ void testOnSuccessFailingField() { } } + static class OnSuccessFailingStaticFieldCase { + + @TempDir(cleanup = ON_SUCCESS) + static Path onSuccessFailingFieldDir; + + @Test + void test() { + TempDirFieldTests.onSuccessFailingFieldDir = onSuccessFailingFieldDir; + fail(); + } + } + + static class OnSuccessFailingStaticFieldWithNestingCase { + + @TempDir(cleanup = ON_SUCCESS) + static Path onSuccessFailingFieldDir; + + @Nested + class NestedTestCase { + + @Test + void test() { + TempDirFieldTests.onSuccessFailingFieldDir = onSuccessFailingFieldDir; + fail(); + } + } + } + } @Nested From 3f6c32b76540ce9c7816c8b77cdcf10df5427eff Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 31 Oct 2023 14:07:41 +0100 Subject: [PATCH 085/142] Avoid class-level errors in tests when running individual test methods --- .../extension/TempDirectoryCleanupTests.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java index c3dfb781f8c8..e4564fe55882 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java @@ -174,11 +174,17 @@ void cleanupModeOnSuccessFailingStaticFieldWithNesting() { @AfterAll static void afterAll() throws IOException { - deleteIfExists(defaultFieldDir); - deleteIfExists(neverFieldDir); - deleteIfExists(alwaysFieldDir); - deleteIfExists(onSuccessFailingFieldDir); - deleteIfExists(onSuccessPassingFieldDir); + deleteIfNotNullAndExists(defaultFieldDir); + deleteIfNotNullAndExists(neverFieldDir); + deleteIfNotNullAndExists(alwaysFieldDir); + deleteIfNotNullAndExists(onSuccessFailingFieldDir); + deleteIfNotNullAndExists(onSuccessPassingFieldDir); + } + + static void deleteIfNotNullAndExists(Path dir) throws IOException { + if (dir != null) { + deleteIfExists(dir); + } } // ------------------------------------------------------------------- @@ -373,11 +379,11 @@ void cleanupModeOnSuccessFailingParameter() { @AfterAll static void afterAll() throws IOException { - deleteIfExists(defaultParameterDir); - deleteIfExists(neverParameterDir); - deleteIfExists(alwaysParameterDir); - deleteIfExists(onSuccessFailingParameterDir); - deleteIfExists(onSuccessPassingParameterDir); + TempDirFieldTests.deleteIfNotNullAndExists(defaultParameterDir); + TempDirFieldTests.deleteIfNotNullAndExists(neverParameterDir); + TempDirFieldTests.deleteIfNotNullAndExists(alwaysParameterDir); + TempDirFieldTests.deleteIfNotNullAndExists(onSuccessFailingParameterDir); + TempDirFieldTests.deleteIfNotNullAndExists(onSuccessPassingParameterDir); } // ------------------------------------------------------------------- From 6dd79b83922e2eda5cce3529b31b59119704f027 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Thu, 2 Nov 2023 09:57:15 +0100 Subject: [PATCH 086/142] Reduce number of store operations --- .../jupiter/engine/extension/TempDirectory.java | 8 ++++++-- .../engine/extension/TempDirectoryCleanupTests.java | 12 +++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java index de2398b94f3e..7ac385561839 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java @@ -116,7 +116,11 @@ public void beforeEach(ExtensionContext context) { private static void installFailureTracker(ExtensionContext context) { context.getStore(NAMESPACE).put(FAILURE_TRACKER, (CloseableResource) () -> context.getParent() // - .ifPresent(it -> it.getStore(NAMESPACE).put(CHILD_FAILED, selfOrChildFailed(context)))); + .ifPresent(it -> { + if (selfOrChildFailed(context)) { + it.getStore(NAMESPACE).put(CHILD_FAILED, true); + } + })); } private void injectStaticFields(ExtensionContext context, Class testClass) { @@ -268,7 +272,7 @@ static CloseablePath createTempDir(TempDirFactory factory, CleanupMode cleanupMo private static boolean selfOrChildFailed(ExtensionContext context) { return context.getExecutionException().isPresent() // - || Boolean.TRUE.equals(context.getStore(NAMESPACE).get(CHILD_FAILED)); + || context.getStore(NAMESPACE).getOrDefault(CHILD_FAILED, Boolean.class, false); } static class CloseablePath implements CloseableResource { diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java index e4564fe55882..4e47ec390bb4 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryCleanupTests.java @@ -24,8 +24,11 @@ import java.nio.file.Path; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.io.CleanupMode; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; @@ -245,16 +248,23 @@ void testOnSuccessFailingField() { } } + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) static class OnSuccessFailingStaticFieldCase { @TempDir(cleanup = ON_SUCCESS) static Path onSuccessFailingFieldDir; @Test - void test() { + @Order(1) + void failing() { TempDirFieldTests.onSuccessFailingFieldDir = onSuccessFailingFieldDir; fail(); } + + @Test + @Order(2) + void passing() { + } } static class OnSuccessFailingStaticFieldWithNestingCase { From 2bb1b83221804f9cefceb787a1201a65efe661c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:17:36 +0000 Subject: [PATCH 087/142] Bump commons-io:commons-io from 2.14.0 to 2.15.0 Bumps commons-io:commons-io from 2.14.0 to 2.15.0. --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c76ea1d96dff..50f240fd88bf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.163" } -commons-io = { module = "commons-io:commons-io", version = "2.14.0" } +commons-io = { module = "commons-io:commons-io", version = "2.15.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.3" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15.1" } From 0a514b9c08f1378708810c3deb9cf81a7e2aea69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 10:50:32 +0000 Subject: [PATCH 088/142] Bump com.gradle:common-custom-user-data-gradle-plugin Bumps com.gradle:common-custom-user-data-gradle-plugin from 1.11.3 to 1.12. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 50f240fd88bf..145f56b8c785 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.163" } commons-io = { module = "commons-io:commons-io", version = "2.15.0" } -gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.11.3" } +gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.12" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15.1" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } From c295788bb031cdf8101ce18e2c15e564721d70b3 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 4 Nov 2023 12:41:35 +0100 Subject: [PATCH 089/142] Polishing --- .../commons/util/ReflectionUtilsTests.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 30a403fe00c6..6544ac5b4c69 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -25,6 +25,7 @@ import static org.junit.platform.commons.function.Try.success; import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.BOTTOM_UP; import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.TOP_DOWN; +import static org.junit.platform.commons.util.ReflectionUtils.findFields; import static org.junit.platform.commons.util.ReflectionUtils.findMethod; import static org.junit.platform.commons.util.ReflectionUtils.findMethods; import static org.junit.platform.commons.util.ReflectionUtils.invokeMethod; @@ -1387,7 +1388,7 @@ void readFieldValuesPreconditions() { @Test void readFieldValuesFromInstance() { - var fields = ReflectionUtils.findFields(ClassWithFields.class, f -> true, TOP_DOWN); + var fields = findFields(ClassWithFields.class, f -> true, TOP_DOWN); var values = ReflectionUtils.readFieldValues(fields, new ClassWithFields()); @@ -1396,7 +1397,7 @@ void readFieldValuesFromInstance() { @Test void readFieldValuesFromClass() { - var fields = ReflectionUtils.findFields(ClassWithFields.class, ReflectionUtils::isStatic, TOP_DOWN); + var fields = findFields(ClassWithFields.class, ReflectionUtils::isStatic, TOP_DOWN); var values = ReflectionUtils.readFieldValues(fields, null); @@ -1405,7 +1406,7 @@ void readFieldValuesFromClass() { @Test void readFieldValuesFromInstanceWithTypeFilterForString() { - var fields = ReflectionUtils.findFields(ClassWithFields.class, isA(String.class), TOP_DOWN); + var fields = findFields(ClassWithFields.class, isA(String.class), TOP_DOWN); var values = ReflectionUtils.readFieldValues(fields, new ClassWithFields(), isA(String.class)); @@ -1414,8 +1415,7 @@ void readFieldValuesFromInstanceWithTypeFilterForString() { @Test void readFieldValuesFromClassWithTypeFilterForString() { - var fields = ReflectionUtils.findFields(ClassWithFields.class, isA(String.class).and(ReflectionUtils::isStatic), - TOP_DOWN); + var fields = findFields(ClassWithFields.class, isA(String.class).and(ReflectionUtils::isStatic), TOP_DOWN); var values = ReflectionUtils.readFieldValues(fields, null, isA(String.class)); @@ -1424,7 +1424,7 @@ void readFieldValuesFromClassWithTypeFilterForString() { @Test void readFieldValuesFromInstanceWithTypeFilterForInteger() { - var fields = ReflectionUtils.findFields(ClassWithFields.class, isA(int.class), TOP_DOWN); + var fields = findFields(ClassWithFields.class, isA(int.class), TOP_DOWN); var values = ReflectionUtils.readFieldValues(fields, new ClassWithFields(), isA(int.class)); @@ -1433,8 +1433,7 @@ void readFieldValuesFromInstanceWithTypeFilterForInteger() { @Test void readFieldValuesFromClassWithTypeFilterForInteger() { - var fields = ReflectionUtils.findFields(ClassWithFields.class, - isA(Integer.class).and(ReflectionUtils::isStatic), TOP_DOWN); + var fields = findFields(ClassWithFields.class, isA(Integer.class).and(ReflectionUtils::isStatic), TOP_DOWN); var values = ReflectionUtils.readFieldValues(fields, null, isA(Integer.class)); @@ -1443,7 +1442,7 @@ void readFieldValuesFromClassWithTypeFilterForInteger() { @Test void readFieldValuesFromInstanceWithTypeFilterForDouble() { - var fields = ReflectionUtils.findFields(ClassWithFields.class, isA(double.class), TOP_DOWN); + var fields = findFields(ClassWithFields.class, isA(double.class), TOP_DOWN); var values = ReflectionUtils.readFieldValues(fields, new ClassWithFields(), isA(double.class)); @@ -1452,8 +1451,7 @@ void readFieldValuesFromInstanceWithTypeFilterForDouble() { @Test void readFieldValuesFromClassWithTypeFilterForDouble() { - var fields = ReflectionUtils.findFields(ClassWithFields.class, isA(Double.class).and(ReflectionUtils::isStatic), - TOP_DOWN); + var fields = findFields(ClassWithFields.class, isA(Double.class).and(ReflectionUtils::isStatic), TOP_DOWN); var values = ReflectionUtils.readFieldValues(fields, null, isA(Double.class)); From f30a8d551795653843e3c44c1af01001bddfd846 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 3 Nov 2023 18:25:52 +0100 Subject: [PATCH 090/142] Apply field predicate before searching type hierarchy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this commit, findFields() and streamFields() in ReflectionSupport as well as findAnnotatedFields() and findAnnotatedFieldValues() in AnnotationSupport first searched for all fields in the type hierarchy and then applied the user-supplied predicate (or "is annotated?" predicate) afterwards. This resulted in fields in subclasses incorrectly "shadowing" package-private fields in superclasses (in a different package) even if the predicate would otherwise exclude the field in such a subclass. For example, given a superclass that declares a package-private static @⁠TempDir "tempDir" field and a subclass (in a different package) that declares a @⁠TempDir "tempDir" field, when JUnit Jupiter looked up @⁠TempDir fields for the subclass, the @⁠TempDir "tempDir" field in the superclass was not found because the @⁠TempDir "tempDir" field shadowed it based solely on the field signature, ignoring the type of annotation sought. To address that, this commit modifies the internal search algorithms in ReflectionUtils so that field predicates are applied while searching the hierarchy for fields. See #3498 Closes #3532 Closes #3533 --- .../release-notes/release-notes-5.10.1.adoc | 12 ++++- .../commons/util/ReflectionUtils.java | 44 ++++++++++++------- .../commons/util/AnnotationUtilsTests.java | 26 +++++++++++ .../commons/util/ReflectionUtilsTests.java | 24 ++++++++++ .../commons/util/pkg1/ClassLevelDir.java | 24 ++++++++++ .../commons/util/pkg1/InstanceLevelDir.java | 24 ++++++++++ ...sWithStaticPackagePrivateTempDirField.java | 23 ++++++++++ ...thNonStaticPackagePrivateTempDirField.java | 26 +++++++++++ 8 files changed, 184 insertions(+), 19 deletions(-) create mode 100644 platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/ClassLevelDir.java create mode 100644 platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/InstanceLevelDir.java create mode 100644 platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateTempDirField.java create mode 100644 platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateTempDirField.java diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc index 65c3aa6055b4..515aa64f41b1 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -15,6 +15,10 @@ JUnit repository on GitHub. ==== Bug Fixes +* Field predicates are now applied while searching the type hierarchy. This fixes bugs in + `findFields(...)` and `streamFields(...)` in `ReflectionSupport` as well as + `findAnnotatedFields(...)` and `findAnnotatedFieldValues(...)` in `AnnotationSupport`. + - See link:https://github.com/junit-team/junit5/issues/3532[issue 3532] for details. * Method predicates are now applied while searching the type hierarchy. This fixes bugs in `findMethods(...)` and `streamMethods(...)` in `ReflectionSupport` as well as `findAnnotatedMethods(...)` in `AnnotationSupport`. @@ -26,16 +30,20 @@ JUnit repository on GitHub. ==== Bug Fixes +* A package-private static field annotated with `@TempDir` is no longer _shadowed_ by a + non-static field annotated with `@TempDir` when the non-static field resides in a + different package and has the same name as the static field. + - See link:https://github.com/junit-team/junit5/issues/3532[issue 3532] for details. * A package-private class-level lifecycle method annotated with `@BeforeAll` or `@AfterAll` is no longer _shadowed_ by a method-level lifecycle method annotated with `@BeforeEach` or `@AfterEach` when the method-level lifecycle method resides in a different package and has the same name as the class-level lifecycle method. - See link:https://github.com/junit-team/junit5/issues/3498[issue 3498] for details. +* The `ON_SUCCESS` cleanup mode of `@TempDir` now takes into account failures of test + methods and nested tests when it's declared on the class level, e.g. as a static field. * The `RandomNumberExtension` example in the <<../user-guide/index.adoc#extensions-RandomNumberExtension, User Guide>> has been updated to properly support `Integer` types as well as non-static field injection. -* The `ON_SUCCESS` cleanup mode of `@TempDir` now takes into account failures of test - methods and nested tests when it's declared on the class level, e.g. as a static field. ==== New Features and Improvements diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 927b97451e0a..ea824ebd23a9 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -1238,6 +1238,7 @@ public static List> findConstructors(Class clazz, Predicate findFields(Class clazz, Predicate predicate, HierarchyTraversalMode traversalMode) { + return streamFields(clazz, predicate, traversalMode).collect(toUnmodifiableList()); } @@ -1252,21 +1253,23 @@ public static Stream streamFields(Class clazz, Predicate predic Preconditions.notNull(predicate, "Predicate must not be null"); Preconditions.notNull(traversalMode, "HierarchyTraversalMode must not be null"); - return findAllFieldsInHierarchy(clazz, traversalMode).stream().filter(predicate); + return findAllFieldsInHierarchy(clazz, predicate, traversalMode).stream(); } - private static List findAllFieldsInHierarchy(Class clazz, HierarchyTraversalMode traversalMode) { + private static List findAllFieldsInHierarchy(Class clazz, Predicate predicate, + HierarchyTraversalMode traversalMode) { + Preconditions.notNull(clazz, "Class must not be null"); Preconditions.notNull(traversalMode, "HierarchyTraversalMode must not be null"); // @formatter:off - List localFields = getDeclaredFields(clazz).stream() + List localFields = getDeclaredFields(clazz, predicate).stream() .filter(field -> !field.isSynthetic()) .collect(toList()); - List superclassFields = getSuperclassFields(clazz, traversalMode).stream() + List superclassFields = getSuperclassFields(clazz, predicate, traversalMode).stream() .filter(field -> !isFieldShadowedByLocalFields(field, localFields)) .collect(toList()); - List interfaceFields = getInterfaceFields(clazz, traversalMode).stream() + List interfaceFields = getInterfaceFields(clazz, predicate, traversalMode).stream() .filter(field -> !isFieldShadowedByLocalFields(field, localFields)) .collect(toList()); // @formatter:on @@ -1529,18 +1532,20 @@ private static List findAllMethodsInHierarchy(Class clazz, Predicate< /** * Custom alternative to {@link Class#getFields()} that sorts the fields - * and converts them to a mutable list. + * which match the supplied predicate and converts them to a mutable list. + * @param predicate the field filter; never {@code null} */ - private static List getFields(Class clazz) { - return toSortedMutableList(clazz.getFields()); + private static List getFields(Class clazz, Predicate predicate) { + return toSortedMutableList(clazz.getFields(), predicate); } /** * Custom alternative to {@link Class#getDeclaredFields()} that sorts the - * fields and converts them to a mutable list. + * fields which match the supplied predicate and converts them to a mutable list. + * @param predicate the field filter; never {@code null} */ - private static List getDeclaredFields(Class clazz) { - return toSortedMutableList(clazz.getDeclaredFields()); + private static List getDeclaredFields(Class clazz, Predicate predicate) { + return toSortedMutableList(clazz.getDeclaredFields(), predicate); } /** @@ -1602,9 +1607,10 @@ private static List getDefaultMethods(Class clazz) { // @formatter:on } - private static List toSortedMutableList(Field[] fields) { + private static List toSortedMutableList(Field[] fields, Predicate predicate) { // @formatter:off return Arrays.stream(fields) + .filter(predicate) .sorted(ReflectionUtils::defaultFieldSorter) // Use toCollection() instead of toList() to ensure list is mutable. .collect(toCollection(ArrayList::new)); @@ -1672,13 +1678,15 @@ private static List getInterfaceMethods(Class clazz, Predicate getInterfaceFields(Class clazz, HierarchyTraversalMode traversalMode) { + private static List getInterfaceFields(Class clazz, Predicate predicate, + HierarchyTraversalMode traversalMode) { + List allInterfaceFields = new ArrayList<>(); for (Class ifc : clazz.getInterfaces()) { - List localInterfaceFields = getFields(ifc); + List localInterfaceFields = getFields(ifc, predicate); // @formatter:off - List superinterfaceFields = getInterfaceFields(ifc, traversalMode).stream() + List superinterfaceFields = getInterfaceFields(ifc, predicate, traversalMode).stream() .filter(field -> !isFieldShadowedByLocalFields(field, localInterfaceFields)) .collect(toList()); // @formatter:on @@ -1694,12 +1702,14 @@ private static List getInterfaceFields(Class clazz, HierarchyTraversal return allInterfaceFields; } - private static List getSuperclassFields(Class clazz, HierarchyTraversalMode traversalMode) { + private static List getSuperclassFields(Class clazz, Predicate predicate, + HierarchyTraversalMode traversalMode) { + Class superclass = clazz.getSuperclass(); if (!isSearchable(superclass)) { return Collections.emptyList(); } - return findAllFieldsInHierarchy(superclass, traversalMode); + return findAllFieldsInHierarchy(superclass, predicate, traversalMode); } private static boolean isFieldShadowedByLocalFields(Field field, List localFields) { diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java index f26f5ab755d3..5dde2c34cbd9 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/AnnotationUtilsTests.java @@ -46,8 +46,12 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.platform.commons.PreconditionViolationException; +import org.junit.platform.commons.util.pkg1.ClassLevelDir; +import org.junit.platform.commons.util.pkg1.InstanceLevelDir; import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateBeforeMethod; +import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateTempDirField; import org.junit.platform.commons.util.pkg1.subpkg.SubclassWithNonStaticPackagePrivateBeforeMethod; +import org.junit.platform.commons.util.pkg1.subpkg.SubclassWithNonStaticPackagePrivateTempDirField; /** * Unit tests for {@link AnnotationUtils}. @@ -504,6 +508,28 @@ private List findShadowingAnnotatedFields(Class ann return findAnnotatedFields(ClassWithShadowedAnnotatedFields.class, annotationType, isStringField); } + /** + * @see https://github.com/junit-team/junit5/issues/3532 + */ + @Test + void findAnnotatedFieldsAppliesPredicateBeforeSearchingTypeHierarchy() throws Exception { + final String TEMP_DIR = "tempDir"; + Class superclass = SuperclassWithStaticPackagePrivateTempDirField.class; + Field staticField = superclass.getDeclaredField(TEMP_DIR); + Class subclass = SubclassWithNonStaticPackagePrivateTempDirField.class; + Field nonStaticField = subclass.getDeclaredField(TEMP_DIR); + + // Prerequisite + var fields = findAnnotatedFields(superclass, ClassLevelDir.class, field -> true); + assertThat(fields).containsExactly(staticField); + + // Actual use cases for this test + fields = findAnnotatedFields(subclass, ClassLevelDir.class, field -> true); + assertThat(fields).containsExactly(staticField); + fields = findAnnotatedFields(subclass, InstanceLevelDir.class, field -> true); + assertThat(fields).containsExactly(nonStaticField); + } + // === findPublicAnnotatedFields() ========================================= @Test diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 6544ac5b4c69..11b3963c3e8e 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -74,7 +74,9 @@ import org.junit.platform.commons.util.ReflectionUtilsTests.OuterClassImplementingInterface.InnerClassImplementingInterface; import org.junit.platform.commons.util.classes.CustomType; import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateBeforeMethod; +import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateTempDirField; import org.junit.platform.commons.util.pkg1.subpkg.SubclassWithNonStaticPackagePrivateBeforeMethod; +import org.junit.platform.commons.util.pkg1.subpkg.SubclassWithNonStaticPackagePrivateTempDirField; /** * Unit tests for {@link ReflectionUtils}. @@ -1379,6 +1381,28 @@ void isGeneric() { } } + /** + * @see https://github.com/junit-team/junit5/issues/3532 + */ + @Test + void findFieldsAppliesPredicateBeforeSearchingTypeHierarchy() throws Exception { + final String TEMP_DIR = "tempDir"; + Class superclass = SuperclassWithStaticPackagePrivateTempDirField.class; + Field staticField = superclass.getDeclaredField(TEMP_DIR); + Class subclass = SubclassWithNonStaticPackagePrivateTempDirField.class; + Field nonStaticField = subclass.getDeclaredField(TEMP_DIR); + + // Prerequisite + var fields = findFields(superclass, ReflectionUtils::isStatic, TOP_DOWN); + assertThat(fields).containsExactly(staticField); + + // Actual use cases for this test + fields = findFields(subclass, ReflectionUtils::isStatic, TOP_DOWN); + assertThat(fields).containsExactly(staticField); + fields = findFields(subclass, ReflectionUtils::isNotStatic, TOP_DOWN); + assertThat(fields).containsExactly(nonStaticField); + } + @Test void readFieldValuesPreconditions() { assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.readFieldValues(null, new Object())); diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/ClassLevelDir.java b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/ClassLevelDir.java new file mode 100644 index 000000000000..d6b94d9d2076 --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/ClassLevelDir.java @@ -0,0 +1,24 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util.pkg1; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Mimics {@code @TempDir}. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ClassLevelDir { +} diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/InstanceLevelDir.java b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/InstanceLevelDir.java new file mode 100644 index 000000000000..bfa4e4ad8b95 --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/InstanceLevelDir.java @@ -0,0 +1,24 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util.pkg1; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Mimics {@code @TempDir}. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface InstanceLevelDir { +} diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateTempDirField.java b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateTempDirField.java new file mode 100644 index 000000000000..4e2bbe7ec696 --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/SuperclassWithStaticPackagePrivateTempDirField.java @@ -0,0 +1,23 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util.pkg1; + +import java.nio.file.Path; + +/** + * @see https://github.com/junit-team/junit5/issues/3532 + */ +public class SuperclassWithStaticPackagePrivateTempDirField { + + @ClassLevelDir + static Path tempDir; + +} diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateTempDirField.java b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateTempDirField.java new file mode 100644 index 000000000000..d7eb33f6a326 --- /dev/null +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/pkg1/subpkg/SubclassWithNonStaticPackagePrivateTempDirField.java @@ -0,0 +1,26 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.util.pkg1.subpkg; + +import java.nio.file.Path; + +import org.junit.platform.commons.util.pkg1.InstanceLevelDir; +import org.junit.platform.commons.util.pkg1.SuperclassWithStaticPackagePrivateTempDirField; + +/** + * @see https://github.com/junit-team/junit5/issues/3532 + */ +public class SubclassWithNonStaticPackagePrivateTempDirField extends SuperclassWithStaticPackagePrivateTempDirField { + + @InstanceLevelDir + Path tempDir; + +} From a670d107cde5818f9cb5adfae94300f740d13fe8 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 4 Nov 2023 14:15:55 +0100 Subject: [PATCH 091/142] Harmonize application of method and field filters in search algorithms This commit consistently applies method predicates in search algorithms analogous to the application of field predicates. See #3498 See #3532 Closes #3534 --- .../commons/util/ReflectionUtils.java | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index ea824ebd23a9..478b3372add0 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -1407,11 +1407,11 @@ private static Optional findMethod(Class clazz, Predicate pre for (Class current = clazz; isSearchable(current); current = current.getSuperclass()) { // Search for match in current type - List methods = current.isInterface() ? getMethods(current) : getDeclaredMethods(current, BOTTOM_UP); - for (Method method : methods) { - if (predicate.test(method)) { - return Optional.of(method); - } + List methods = current.isInterface() ? getMethods(current, predicate) + : getDeclaredMethods(current, predicate, BOTTOM_UP); + if (!methods.isEmpty()) { + // Since the predicate has already been applied, return the first match. + return Optional.of(methods.get(0)); } // Search for match in interfaces implemented by current type @@ -1506,8 +1506,8 @@ private static List findAllMethodsInHierarchy(Class clazz, Predicate< Preconditions.notNull(traversalMode, "HierarchyTraversalMode must not be null"); // @formatter:off - List localMethods = getDeclaredMethods(clazz, traversalMode).stream() - .filter(predicate.and(method -> !method.isSynthetic())) + List localMethods = getDeclaredMethods(clazz, predicate, traversalMode).stream() + .filter(method -> !method.isSynthetic()) .collect(toList()); List superclassMethods = getSuperclassMethods(clazz, predicate, traversalMode).stream() .filter(method -> !isMethodShadowedByLocalMethods(method, localMethods)) @@ -1533,7 +1533,6 @@ private static List findAllMethodsInHierarchy(Class clazz, Predicate< /** * Custom alternative to {@link Class#getFields()} that sorts the fields * which match the supplied predicate and converts them to a mutable list. - * @param predicate the field filter; never {@code null} */ private static List getFields(Class clazz, Predicate predicate) { return toSortedMutableList(clazz.getFields(), predicate); @@ -1542,7 +1541,6 @@ private static List getFields(Class clazz, Predicate predicate) /** * Custom alternative to {@link Class#getDeclaredFields()} that sorts the * fields which match the supplied predicate and converts them to a mutable list. - * @param predicate the field filter; never {@code null} */ private static List getDeclaredFields(Class clazz, Predicate predicate) { return toSortedMutableList(clazz.getDeclaredFields(), predicate); @@ -1550,24 +1548,26 @@ private static List getDeclaredFields(Class clazz, Predicate pr /** * Custom alternative to {@link Class#getMethods()} that sorts the methods - * and converts them to a mutable list. + * which match the supplied predicate and converts them to a mutable list. */ - private static List getMethods(Class clazz) { - return toSortedMutableList(clazz.getMethods()); + private static List getMethods(Class clazz, Predicate predicate) { + return toSortedMutableList(clazz.getMethods(), predicate); } /** * Custom alternative to {@link Class#getDeclaredMethods()} that sorts the - * methods and converts them to a mutable list. + * methods which match the supplied predicate and converts them to a mutable list. * *

In addition, the list returned by this method includes interface * default methods which are either prepended or appended to the list of * declared methods depending on the supplied traversal mode. */ - private static List getDeclaredMethods(Class clazz, HierarchyTraversalMode traversalMode) { + private static List getDeclaredMethods(Class clazz, Predicate predicate, + HierarchyTraversalMode traversalMode) { + // Note: getDefaultMethods() already sorts the methods, - List defaultMethods = getDefaultMethods(clazz); - List declaredMethods = toSortedMutableList(clazz.getDeclaredMethods()); + List defaultMethods = getDefaultMethods(clazz, predicate); + List declaredMethods = toSortedMutableList(clazz.getDeclaredMethods(), predicate); // Take the traversal mode into account in order to retain the inherited // nature of interface default methods. @@ -1584,23 +1584,23 @@ private static List getDeclaredMethods(Class clazz, HierarchyTraversa /** * Get a sorted, mutable list of all default methods present in interfaces * implemented by the supplied class which are also visible within - * the supplied class. + * the supplied class and match the supplied predicate. * * @see Method Visibility * in the Java Language Specification */ - private static List getDefaultMethods(Class clazz) { + private static List getDefaultMethods(Class clazz, Predicate predicate) { // @formatter:off // Visible default methods are interface default methods that have not // been overridden. List visibleDefaultMethods = Arrays.stream(clazz.getMethods()) - .filter(Method::isDefault) + .filter(predicate.and(Method::isDefault)) .collect(toCollection(ArrayList::new)); if (visibleDefaultMethods.isEmpty()) { return visibleDefaultMethods; } return Arrays.stream(clazz.getInterfaces()) - .map(ReflectionUtils::getMethods) + .map(ifc -> getMethods(ifc, predicate)) .flatMap(List::stream) .filter(visibleDefaultMethods::contains) .collect(toCollection(ArrayList::new)); @@ -1617,9 +1617,10 @@ private static List toSortedMutableList(Field[] fields, Predicate // @formatter:on } - private static List toSortedMutableList(Method[] methods) { + private static List toSortedMutableList(Method[] methods, Predicate predicate) { // @formatter:off return Arrays.stream(methods) + .filter(predicate) .sorted(ReflectionUtils::defaultMethodSorter) // Use toCollection() instead of toList() to ensure list is mutable. .collect(toCollection(ArrayList::new)); @@ -1658,8 +1659,8 @@ private static List getInterfaceMethods(Class clazz, Predicate ifc : clazz.getInterfaces()) { // @formatter:off - List localInterfaceMethods = getMethods(ifc).stream() - .filter(predicate.and(method -> !isAbstract(method))) + List localInterfaceMethods = getMethods(ifc, predicate).stream() + .filter(method -> !isAbstract(method)) .collect(toList()); List superinterfaceMethods = getInterfaceMethods(ifc, predicate, traversalMode).stream() From 4a1046de42c9322c376b2dc2d82c321e8862c34b Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 5 Nov 2023 17:17:22 +0100 Subject: [PATCH 092/142] Fix typo in AfterAll documentation --- .../src/main/java/org/junit/jupiter/api/AfterAll.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterAll.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterAll.java index 52743ebef416..40f2e949a3d9 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterAll.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterAll.java @@ -40,7 +40,7 @@ * methods may optionally declare parameters to be resolved by * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolvers}. * - *

Using {@code private} visibility for {@code @BeforeAll} methods is + *

Using {@code private} visibility for {@code @AfterAll} methods is * strongly discouraged and will be disallowed in a future release. * *

Inheritance and Execution Order

From cbb70c3e517cb1dfd33c2a266901c10fb85de479 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 5 Nov 2023 17:48:47 +0100 Subject: [PATCH 093/142] Release 5.10.1 --- README.md | 2 +- .../src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 78fb026ea940..2f3c0be2b3ad 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This repository is the home of _JUnit 5_. ## Latest Releases -- General Availability (GA): [JUnit 5.10.0](https://github.com/junit-team/junit5/releases/tag/r5.10.0) (July 23, 2023) +- General Availability (GA): [JUnit 5.10.1](https://github.com/junit-team/junit5/releases/tag/r5.10.1) (November 5, 2023) - Preview (Milestone/Release Candidate): N/A ## Documentation diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc index 515aa64f41b1..af0ac43916b4 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.1.adoc @@ -1,7 +1,7 @@ [[release-notes-5.10.1]] == 5.10.1 -*Date of Release:* ❓ +*Date of Release:* November 5, 2023 *Scope:* minor bug fixes and improvements since 5.10.0. From a4efa56a7c33f17edf5bfe6f8f16be419f7b9f98 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 5 Nov 2023 18:28:33 +0100 Subject: [PATCH 094/142] Fix path to component diagram --- documentation/documentation.gradle.kts | 4 +++- documentation/src/docs/asciidoc/user-guide/appendix.adoc | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/documentation/documentation.gradle.kts b/documentation/documentation.gradle.kts index ea2755cba333..ad16a4294821 100644 --- a/documentation/documentation.gradle.kts +++ b/documentation/documentation.gradle.kts @@ -231,6 +231,9 @@ tasks { include("**/images/**/*.png") include("**/images/**/*.svg") } + from(componentDiagram) { + into("user-guide/images") + } } // Temporary workaround for https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues/599 @@ -256,7 +259,6 @@ tasks { "experimentalApisTableFile" to experimentalApisTableFile.get(), "deprecatedApisTableFile" to deprecatedApisTableFile.get(), "standaloneConsoleLauncherShadowedArtifactsFile" to standaloneConsoleLauncherShadowedArtifactsFile.get(), - "componentDiagramFile" to componentDiagram.get(), "outdir" to outputDir.absolutePath, "source-highlighter" to "rouge", "rouge-style" to "junit", diff --git a/documentation/src/docs/asciidoc/user-guide/appendix.adoc b/documentation/src/docs/asciidoc/user-guide/appendix.adoc index 06a72fb4880b..7582ba606f0b 100644 --- a/documentation/src/docs/asciidoc/user-guide/appendix.adoc +++ b/documentation/src/docs/asciidoc/user-guide/appendix.adoc @@ -133,4 +133,4 @@ following _OpenTest4J_ JAR. [[dependency-diagram]] === Dependency Diagram -image::{componentDiagramFile}[] +image::component-diagram.svg[] From 67bf8061144cae7394ff166861f80e2ac686f708 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 05:19:45 +0000 Subject: [PATCH 095/142] Bump github/combine-prs from 4.0.0 to 4.1.0 Bumps [github/combine-prs](https://github.com/github/combine-prs) from 4.0.0 to 4.1.0. - [Release notes](https://github.com/github/combine-prs/releases) - [Commits](https://github.com/github/combine-prs/compare/v4.0.0...v4.1.0) --- updated-dependencies: - dependency-name: github/combine-prs dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/combine-prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml index d0c826295265..6ef40f908963 100644 --- a/.github/workflows/combine-prs.yml +++ b/.github/workflows/combine-prs.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - name: combine-prs - uses: github/combine-prs@v4.0.0 + uses: github/combine-prs@v4.1.0 with: github_token: ${{ secrets.GH_TOKEN }} From 4f6b3c184a9886eca1e495f2c57a5e601cb68b0b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 05:08:57 +0000 Subject: [PATCH 096/142] Bump io.github.classgraph:classgraph from 4.8.163 to 4.8.164 Bumps [io.github.classgraph:classgraph](https://github.com/classgraph/classgraph) from 4.8.163 to 4.8.164. - [Release notes](https://github.com/classgraph/classgraph/releases) - [Commits](https://github.com/classgraph/classgraph/compare/classgraph-4.8.163...classgraph-4.8.164) --- updated-dependencies: - dependency-name: io.github.classgraph:classgraph dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 145f56b8c785..6271e0081b47 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } -classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.163" } +classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.164" } commons-io = { module = "commons-io:commons-io", version = "2.15.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.12" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } From 9e791294874d84934fc130f6385b239651d19387 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 05:09:07 +0000 Subject: [PATCH 097/142] Bump me.champeau.jmh from 0.7.1 to 0.7.2 Bumps me.champeau.jmh from 0.7.1 to 0.7.2. --- updated-dependencies: - dependency-name: me.champeau.jmh dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6271e0081b47..9c75ecdb52c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -78,7 +78,7 @@ asciidoctorConvert = { id = "org.asciidoctor.jvm.convert", version.ref = "asciid asciidoctorPdf = { id = "org.asciidoctor.jvm.pdf", version.ref = "asciidoctor-plugins" } buildParameters = { id = "org.gradlex.build-parameters", version = "1.4.3" } gitPublish = { id = "org.ajoberstar.git-publish", version = "4.2.1" } -jmh = { id = "me.champeau.jmh", version = "0.7.1" } +jmh = { id = "me.champeau.jmh", version = "0.7.2" } nohttp = { id = "io.spring.nohttp", version = "0.0.11" } nexusPublish = { id = "io.github.gradle-nexus.publish-plugin", version = "2.0.0-rc-1" } plantuml = { id = "io.freefair.plantuml", version = "8.4" } From 629d94b9408e13bcd3b711fe12a5e429b0ee16f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 05:09:16 +0000 Subject: [PATCH 098/142] Bump org.mockito:mockito-junit-jupiter from 5.6.0 to 5.7.0 Bumps [org.mockito:mockito-junit-jupiter](https://github.com/mockito/mockito) from 5.6.0 to 5.7.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.6.0...v5.7.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9c75ecdb52c0..c8ec96459b26 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -53,7 +53,7 @@ log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4 maven = { module = "org.apache.maven:apache-maven", version = "3.9.5" } mavenSurefirePlugin = { module = "org.apache.maven.plugins:maven-surefire-plugin", version.ref = "surefire" } memoryfilesystem = { module = "com.github.marschall:memoryfilesystem", version = "2.6.1" } -mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.6.0" } +mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.7.0" } opentest4j = { module = "org.opentest4j:opentest4j", version.ref = "opentest4j" } openTestReporting-events = { module = "org.opentest4j.reporting:open-test-reporting-events", version.ref = "openTestReporting" } openTestReporting-tooling = { module = "org.opentest4j.reporting:open-test-reporting-tooling", version.ref = "openTestReporting" } From 1d89dd3206a4edbfb829880af208cd2dfb49ed78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 05:09:25 +0000 Subject: [PATCH 099/142] Bump com.tngtech.archunit:archunit-junit5 from 1.1.0 to 1.2.0 Bumps [com.tngtech.archunit:archunit-junit5](https://github.com/TNG/ArchUnit) from 1.1.0 to 1.2.0. - [Release notes](https://github.com/TNG/ArchUnit/releases) - [Commits](https://github.com/TNG/ArchUnit/compare/v1.1.0...v1.2.0) --- updated-dependencies: - dependency-name: com.tngtech.archunit:archunit-junit5 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c8ec96459b26..d4faeed03f3f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ ant = { module = "org.apache.ant:ant", version.ref = "ant" } ant-junit = { module = "org.apache.ant:ant-junit", version.ref = "ant" } ant-junitlauncher = { module = "org.apache.ant:ant-junitlauncher", version.ref = "ant" } apiguardian = { module = "org.apiguardian:apiguardian-api", version.ref = "apiguardian" } -archunit = { module = "com.tngtech.archunit:archunit-junit5", version = "1.1.0" } +archunit = { module = "com.tngtech.archunit:archunit-junit5", version = "1.2.0" } assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } From fe303b49cd7b3c2b602d4998f90d88ede2d65aa4 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 10 Nov 2023 16:02:37 +0100 Subject: [PATCH 100/142] Remove deprecated ReflectionUtils.getOutermostInstance() method ReflectionUtils.getOutermostInstance() has been deprecated since JUnit 5.4 due to changes made in conjunction with #1650. Furthermore, since Java 18, one can no longer rely on the presence of a `this$` field that holds a reference to the enclosing instance. In light of that, the team has decided to remove this deprecated, internal method. See also: https://bugs.openjdk.org/browse/JDK-8271623 Closes #3552 --- .../commons/util/ReflectionUtils.java | 51 ------------------- .../commons/util/ReflectionUtilsTests.java | 25 --------- 2 files changed, 76 deletions(-) diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java index 478b3372add0..b7e45171dbaf 100644 --- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java @@ -927,57 +927,6 @@ else if (methodPart.endsWith(")")) { return new String[] { className, methodName, methodParameters }; } - /** - * Get the outermost instance of the required type, searching recursively - * through enclosing instances. - * - *

If the supplied inner object is of the required type, it will be - * returned. - * - * @param inner the inner object from which to begin the search; never {@code null} - * @param requiredType the required type of the outermost instance; never {@code null} - * @return an {@code Optional} containing the outermost instance; never {@code null} - * but potentially empty - * @deprecated Please discontinue use of this method since it relies on internal - * implementation details of the JDK that may not work in the future. - */ - @API(status = DEPRECATED, since = "1.4") - @Deprecated - public static Optional getOutermostInstance(Object inner, Class requiredType) { - Preconditions.notNull(inner, "inner object must not be null"); - Preconditions.notNull(requiredType, "requiredType must not be null"); - - if (requiredType.isInstance(inner)) { - return Optional.of(inner); - } - - Optional candidate = getOuterInstance(inner); - if (candidate.isPresent()) { - return getOutermostInstance(candidate.get(), requiredType); - } - - return Optional.empty(); - } - - private static Optional getOuterInstance(Object inner) { - // This is risky since it depends on the name of the field which is nowhere guaranteed - // but has been stable so far in all JDKs - - // @formatter:off - return Arrays.stream(inner.getClass().getDeclaredFields()) - .filter(field -> field.getName().startsWith("this$")) - .findFirst() - .map(field -> { - try { - return makeAccessible(field).get(inner); - } - catch (Throwable t) { - throw ExceptionUtils.throwAsUncheckedException(t); - } - }); - // @formatter:on - } - public static Set getAllClasspathRootDirectories() { // This is quite a hack, since sometimes the classpath is quite different String fullClassPath = System.getProperty("java.class.path"); diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java index 11b3963c3e8e..136cb77a71e8 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java @@ -707,31 +707,6 @@ void parseFullyQualifiedMethodNameForMethodWithMultipleParameters() { .containsExactly("com.example.Test", "method", "int, java.lang.Object"); } - @Test - @SuppressWarnings("deprecation") - void getOutermostInstancePreconditions() { - // @formatter:off - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.getOutermostInstance(null, null)); - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.getOutermostInstance(null, Object.class)); - assertThrows(PreconditionViolationException.class, () -> ReflectionUtils.getOutermostInstance(new Object(), null)); - // @formatter:on - } - - @Test - @SuppressWarnings("deprecation") - void getOutermostInstance() { - var firstClass = new FirstClass(); - var secondClass = firstClass.new SecondClass(); - var thirdClass = secondClass.new ThirdClass(); - - assertThat(ReflectionUtils.getOutermostInstance(thirdClass, FirstClass.SecondClass.ThirdClass.class))// - .contains(thirdClass); - assertThat(ReflectionUtils.getOutermostInstance(thirdClass, FirstClass.SecondClass.class))// - .contains(secondClass); - assertThat(ReflectionUtils.getOutermostInstance(thirdClass, FirstClass.class)).contains(firstClass); - assertThat(ReflectionUtils.getOutermostInstance(thirdClass, String.class)).isEmpty(); - } - @Test void getAllClasspathRootDirectories(@TempDir Path tempDirectory) throws Exception { var root1 = tempDirectory.resolve("root1").toAbsolutePath(); From a0511cca0a5566a7af96bf6d20e402f3a41b9900 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 05:52:54 +0000 Subject: [PATCH 101/142] Bump org.apache.maven.plugins:maven-surefire-plugin from 3.2.1 to 3.2.2 Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.1 to 3.2.2. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.1...surefire-3.2.2) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-surefire-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d4faeed03f3f..07bfe994a47d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,7 @@ ktlint = "0.48.2" log4j = "2.21.1" opentest4j = "1.3.0" openTestReporting = "0.1.0-M1" -surefire = "3.2.1" +surefire = "3.2.2" xmlunit = "2.9.1" [libraries] From de368b2def9bf72a4755335e071fd22b7511671e Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 17 Nov 2023 09:10:49 +0100 Subject: [PATCH 102/142] Update security policy to reflect 5.10 release --- SECURITY.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index fca52da512fa..cb9359153b13 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,10 +2,10 @@ ## Supported Versions -| Version | Supported | -| ------- | ------------------ | -| 5.9.x | :white_check_mark: | -| < 5.9 | :x: | +| Version | Supported | +| -------- | ------------------ | +| 5.10.x | :white_check_mark: | +| < 5.10 | :x: | ## Reporting a Vulnerability From 6687a767ac653ee93ce57cc25d38dc2278b9e22a Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Thu, 9 Nov 2023 08:03:42 +0100 Subject: [PATCH 103/142] Upgradle to 8.5-rc-2 --- gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 43462 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..d64cd4917707c1f8861d8cb53dd15194d4248596 100644 GIT binary patch literal 43462 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 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 46671acb6e14..a6d2c525ae57 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionSha256Sum=547d33f88a30b6d9666c79fde614b1e5a1a3e2f86216bc70c4c7e3421f0d4627 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-rc-2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 89303135ba1621ac2d184e24ccdf378c6055bb75 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 17 Nov 2023 08:59:03 +0100 Subject: [PATCH 104/142] Update build and test to require Java 21 --- .github/actions/run-gradle/action.yml | 2 +- .github/workflows/cross-version.yml | 2 +- .github/workflows/main.yml | 2 +- README.md | 4 ++-- gradle/plugins/common/src/main/kotlin/JavaLibraryExtension.kt | 2 +- .../kotlin/junitbuild.java-toolchain-conventions.gradle.kts | 2 +- gradle/plugins/settings.gradle.kts | 2 +- .../params/converter/DefaultArgumentConverterTests.java | 1 + 8 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/actions/run-gradle/action.yml b/.github/actions/run-gradle/action.yml index a4b1bc129f6c..d91435a95ca5 100644 --- a/.github/actions/run-gradle/action.yml +++ b/.github/actions/run-gradle/action.yml @@ -12,7 +12,7 @@ runs: id: setup-gradle-jdk with: distribution: temurin - java-version: 17 + java-version: 21 - uses: gradle/gradle-build-action@v2 env: JAVA_HOME: ${{ steps.setup-gradle-jdk.outputs.path }} diff --git a/.github/workflows/cross-version.yml b/.github/workflows/cross-version.yml index 5a9a309ab286..e71a1adf00dd 100644 --- a/.github/workflows/cross-version.yml +++ b/.github/workflows/cross-version.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - jdk: [21, 22] + jdk: [22] name: "OpenJDK ${{ matrix.jdk }}" runs-on: ubuntu-latest steps: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0fef409ed53d..f4cde61a60b1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,7 +31,7 @@ jobs: uses: graalvm/setup-graalvm@v1 with: version: 'latest' - java-version: '17' + java-version: '21' components: 'native-image' github-token: ${{ secrets.GITHUB_TOKEN }} - name: Build diff --git a/README.md b/README.md index 2f3c0be2b3ad..a477d7e00f04 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ task outputs from previous CI builds. ## Building from Source -You need [JDK 17] to build JUnit 5. [Gradle toolchains] are used to detect and +You need [JDK 21] to build JUnit 5. [Gradle toolchains] are used to detect and potentially download additional JDKs for compilation and test execution. All modules can be _built_ and _tested_ with the [Gradle Wrapper] using the following command. @@ -100,7 +100,7 @@ See also for releases and [Gradle Wrapper]: https://docs.gradle.org/current/userguide/gradle_wrapper.html#sec:using_wrapper [JaCoCo]: https://www.eclemma.org/jacoco/ [Javadoc]: https://junit.org/junit5/docs/current/api/ -[JDK 17]: https://foojay.io/almanac/java-17/ +[JDK 21]: https://foojay.io/almanac/java-21/ [Release Notes]: https://junit.org/junit5/docs/current/release-notes/ [Samples]: https://github.com/junit-team/junit5-samples [StackOverflow]: https://stackoverflow.com/questions/tagged/junit5 diff --git a/gradle/plugins/common/src/main/kotlin/JavaLibraryExtension.kt b/gradle/plugins/common/src/main/kotlin/JavaLibraryExtension.kt index 834374bf06c6..64a61da7fb7b 100644 --- a/gradle/plugins/common/src/main/kotlin/JavaLibraryExtension.kt +++ b/gradle/plugins/common/src/main/kotlin/JavaLibraryExtension.kt @@ -2,6 +2,6 @@ import org.gradle.api.JavaVersion open class JavaLibraryExtension { var mainJavaVersion: JavaVersion = JavaVersion.VERSION_1_8 - var testJavaVersion: JavaVersion = JavaVersion.VERSION_17 + var testJavaVersion: JavaVersion = JavaVersion.VERSION_21 var configureRelease: Boolean = true } diff --git a/gradle/plugins/common/src/main/kotlin/junitbuild.java-toolchain-conventions.gradle.kts b/gradle/plugins/common/src/main/kotlin/junitbuild.java-toolchain-conventions.gradle.kts index 68735c0c9168..41f9376e8dbd 100644 --- a/gradle/plugins/common/src/main/kotlin/junitbuild.java-toolchain-conventions.gradle.kts +++ b/gradle/plugins/common/src/main/kotlin/junitbuild.java-toolchain-conventions.gradle.kts @@ -5,7 +5,7 @@ plugins { } project.pluginManager.withPlugin("java") { - val defaultLanguageVersion = JavaLanguageVersion.of(17) + val defaultLanguageVersion = JavaLanguageVersion.of(21) val javaLanguageVersion = buildParameters.javaToolchainVersion.map { JavaLanguageVersion.of(it) }.getOrElse(defaultLanguageVersion) val extension = the() diff --git a/gradle/plugins/settings.gradle.kts b/gradle/plugins/settings.gradle.kts index 0b948c46d94f..43bfc1bd7621 100644 --- a/gradle/plugins/settings.gradle.kts +++ b/gradle/plugins/settings.gradle.kts @@ -1,4 +1,4 @@ -val expectedJavaVersion = JavaVersion.VERSION_17 +val expectedJavaVersion = JavaVersion.VERSION_21 val actualJavaVersion = JavaVersion.current() require(actualJavaVersion == expectedJavaVersion) { "The JUnit 5 build must be executed with Java ${expectedJavaVersion.majorVersion}. Currently executing with Java ${actualJavaVersion.majorVersion}." diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java index f801058f4e59..76d432b9564c 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java @@ -338,6 +338,7 @@ void convertsStringToCurrency() { } @Test + @SuppressWarnings("deprecation") void convertsStringToLocale() { assertConverts("en", Locale.class, Locale.ENGLISH); assertConverts("en_us", Locale.class, new Locale(Locale.US.toString())); From 6238d5545851436d3760732a1ef58e67f880d52d Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 17 Nov 2023 10:08:39 +0100 Subject: [PATCH 105/142] Introduce build parameter to explicitly enable/disable signing The new `publishing.signArtifacts` can be used to explicitly enable (e.g. for testing) or disable signing of artifacts when publishing to a Maven repository. --- gradle/plugins/build-parameters/build.gradle.kts | 5 +++++ .../kotlin/junitbuild.publishing-conventions.gradle.kts | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/gradle/plugins/build-parameters/build.gradle.kts b/gradle/plugins/build-parameters/build.gradle.kts index f70f2d8bc062..49148effecb7 100644 --- a/gradle/plugins/build-parameters/build.gradle.kts +++ b/gradle/plugins/build-parameters/build.gradle.kts @@ -72,4 +72,9 @@ buildParameters { description = "Configures the number of times failing test are retried" } } + group("publishing") { + bool("signArtifacts") { + description = "Sign artifacts before publishing them to Maven repos" + } + } } diff --git a/gradle/plugins/common/src/main/kotlin/junitbuild.publishing-conventions.gradle.kts b/gradle/plugins/common/src/main/kotlin/junitbuild.publishing-conventions.gradle.kts index 44d693b44779..ad877035e1f3 100644 --- a/gradle/plugins/common/src/main/kotlin/junitbuild.publishing-conventions.gradle.kts +++ b/gradle/plugins/common/src/main/kotlin/junitbuild.publishing-conventions.gradle.kts @@ -40,16 +40,16 @@ tasks.withType().configureEach { dependsOn(tasks.build) } +val signArtifacts = buildParameters.publishing.signArtifacts.getOrElse(!(isSnapshot || buildParameters.ci)) + signing { useGpgCmd() sign(publishing.publications) - isRequired = !(isSnapshot || buildParameters.ci) + isRequired = signArtifacts } tasks.withType().configureEach { - onlyIf { - !isSnapshot // Gradle Module Metadata currently does not support signing snapshots - } + enabled = signArtifacts } publishing { From 2d7f9f4ee6b0bb9c8f83be96f3c7a7c16154fd75 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Fri, 17 Nov 2023 13:53:42 +0100 Subject: [PATCH 106/142] Update link to The Java Version Almanac Backed by https://github.com/marchof/java-almanac --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a477d7e00f04..5e0a293bffa7 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ See also for releases and [Gradle Wrapper]: https://docs.gradle.org/current/userguide/gradle_wrapper.html#sec:using_wrapper [JaCoCo]: https://www.eclemma.org/jacoco/ [Javadoc]: https://junit.org/junit5/docs/current/api/ -[JDK 21]: https://foojay.io/almanac/java-21/ +[JDK 21]: https://javaalmanac.io/jdk/21/ [Release Notes]: https://junit.org/junit5/docs/current/release-notes/ [Samples]: https://github.com/junit-team/junit5-samples [StackOverflow]: https://stackoverflow.com/questions/tagged/junit5 From f892e8153736a20d7bfd9c8687d79ab775968544 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 17 Nov 2023 17:34:55 +0100 Subject: [PATCH 107/142] Upgradle to 8.5-rc-3 --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a6d2c525ae57..bed1ac8ff1ac 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=547d33f88a30b6d9666c79fde614b1e5a1a3e2f86216bc70c4c7e3421f0d4627 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-rc-2-bin.zip +distributionSha256Sum=7207f771dac48bfe19d5990c8f1e7e5f3d5e8b2b98e09ad9a4c484af537f86b2 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-rc-3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 8d0deb0f99e14bf9367b49a848edb7706f63bf6d Mon Sep 17 00:00:00 2001 From: shartte Date: Sun, 19 Nov 2023 13:29:21 +0100 Subject: [PATCH 108/142] Include LauncherInterceptor in launcher module declaration --- .../docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc | 2 ++ .../src/module/org.junit.platform.launcher/module-info.java | 3 +++ .../jar-describe-module/junit-platform-launcher.expected.txt | 1 + 3 files changed, 6 insertions(+) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc index f428b0e5a636..748c0412c6ca 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc @@ -16,6 +16,8 @@ JUnit repository on GitHub. ==== Bug Fixes * ❓ +* Fixes use of the launcher as a Java module when `junit.platform.launcher.interceptors.enabled` is enabled + - See link:https://github.com/junit-team/junit5/issues/3561[issue 3561] for details. ==== Deprecations and Breaking Changes diff --git a/junit-platform-launcher/src/module/org.junit.platform.launcher/module-info.java b/junit-platform-launcher/src/module/org.junit.platform.launcher/module-info.java index 9501caff5a6a..9d79f3f4166a 100644 --- a/junit-platform-launcher/src/module/org.junit.platform.launcher/module-info.java +++ b/junit-platform-launcher/src/module/org.junit.platform.launcher/module-info.java @@ -16,6 +16,8 @@ * @since 1.0 * @uses org.junit.platform.engine.TestEngine * @uses org.junit.platform.launcher.LauncherDiscoveryListener + * @uses org.junit.platform.launcher.LauncherInterceptor + * @uses org.junit.platform.launcher.LauncherSessionListener * @uses org.junit.platform.launcher.PostDiscoveryFilter * @uses org.junit.platform.launcher.TestExecutionListener */ @@ -32,6 +34,7 @@ uses org.junit.platform.engine.TestEngine; uses org.junit.platform.launcher.LauncherDiscoveryListener; + uses org.junit.platform.launcher.LauncherInterceptor; uses org.junit.platform.launcher.LauncherSessionListener; uses org.junit.platform.launcher.PostDiscoveryFilter; uses org.junit.platform.launcher.TestExecutionListener; diff --git a/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-launcher.expected.txt b/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-launcher.expected.txt index 1461169b0fee..41bb2afac024 100644 --- a/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-launcher.expected.txt +++ b/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-launcher.expected.txt @@ -10,6 +10,7 @@ requires org.junit.platform.commons transitive requires org.junit.platform.engine transitive uses org.junit.platform.engine.TestEngine uses org.junit.platform.launcher.LauncherDiscoveryListener +uses org.junit.platform.launcher.LauncherInterceptor uses org.junit.platform.launcher.LauncherSessionListener uses org.junit.platform.launcher.PostDiscoveryFilter uses org.junit.platform.launcher.TestExecutionListener From 93251d93647b7ae5131e47b84139433bd066a87d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 05:18:01 +0000 Subject: [PATCH 109/142] Bump io.github.classgraph:classgraph from 4.8.164 to 4.8.165 Bumps [io.github.classgraph:classgraph](https://github.com/classgraph/classgraph) from 4.8.164 to 4.8.165. - [Release notes](https://github.com/classgraph/classgraph/releases) - [Commits](https://github.com/classgraph/classgraph/compare/classgraph-4.8.164...classgraph-4.8.165) --- updated-dependencies: - dependency-name: io.github.classgraph:classgraph dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 07bfe994a47d..a00478af9072 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -29,7 +29,7 @@ assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } -classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.164" } +classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.165" } commons-io = { module = "commons-io:commons-io", version = "2.15.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.12" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } From f3377ad3497df1b99ccc11e4fdcec4a542d4f684 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 05:18:09 +0000 Subject: [PATCH 110/142] Bump com.puppycrawl.tools:checkstyle from 10.12.4 to 10.12.5 Bumps [com.puppycrawl.tools:checkstyle](https://github.com/checkstyle/checkstyle) from 10.12.4 to 10.12.5. - [Release notes](https://github.com/checkstyle/checkstyle/releases) - [Commits](https://github.com/checkstyle/checkstyle/compare/checkstyle-10.12.4...checkstyle-10.12.5) --- updated-dependencies: - dependency-name: com.puppycrawl.tools:checkstyle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a00478af9072..9ec300362dcc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ asciidoctorj-pdf = "2.3.9" asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gradle.kts can be removed when upgrading assertj = "3.24.2" bnd = "7.0.0" -checkstyle = "10.12.4" +checkstyle = "10.12.5" gradleVersionsPlugin = "0.49.0" jacoco = "0.8.7" jmh = "1.37" From 2b0919d9c94b0ca2f833c6699aca4fa704220ed5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 05:18:15 +0000 Subject: [PATCH 111/142] Bump com.github.marschall:memoryfilesystem from 2.6.1 to 2.7.0 Bumps [com.github.marschall:memoryfilesystem](https://github.com/marschall/memoryfilesystem) from 2.6.1 to 2.7.0. - [Release notes](https://github.com/marschall/memoryfilesystem/releases) - [Commits](https://github.com/marschall/memoryfilesystem/compare/2.6.1...2.7.0) --- updated-dependencies: - dependency-name: com.github.marschall:memoryfilesystem dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9ec300362dcc..8b56c252d1a7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -52,7 +52,7 @@ log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "lo log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4j" } maven = { module = "org.apache.maven:apache-maven", version = "3.9.5" } mavenSurefirePlugin = { module = "org.apache.maven.plugins:maven-surefire-plugin", version.ref = "surefire" } -memoryfilesystem = { module = "com.github.marschall:memoryfilesystem", version = "2.6.1" } +memoryfilesystem = { module = "com.github.marschall:memoryfilesystem", version = "2.7.0" } mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.7.0" } opentest4j = { module = "org.opentest4j:opentest4j", version.ref = "opentest4j" } openTestReporting-events = { module = "org.opentest4j.reporting:open-test-reporting-events", version.ref = "openTestReporting" } From 33753cfdbca435fab2e4e73ee3ec88ee3c80168f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 06:02:10 +0000 Subject: [PATCH 112/142] Bump actions/github-script from 6 to 7 Bumps [actions/github-script](https://github.com/actions/github-script) from 6 to 7. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/github-script dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/issue-labels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue-labels.yml b/.github/workflows/issue-labels.yml index 763dfe889565..b91cf84c462b 100644 --- a/.github/workflows/issue-labels.yml +++ b/.github/workflows/issue-labels.yml @@ -9,7 +9,7 @@ jobs: permissions: issues: write steps: - - uses: actions/github-script@v6 + - uses: actions/github-script@v7 with: script: | github.rest.issues.addLabels({ From 30dbf58c77f477fe8a4645ba320148f653246d3e Mon Sep 17 00:00:00 2001 From: Juliette de Rancourt Date: Tue, 21 Nov 2023 18:12:51 +0100 Subject: [PATCH 113/142] Introduce `StringConversionSupport` in `junit-platform-commons` (#3507) --- .../release-notes-5.11.0-M1.adoc | 3 +- .../converter/DefaultArgumentConverter.java | 50 ++--- .../DefaultArgumentConverterTests.java | 4 + .../conversion/ConversionException.java | 37 ++++ .../FallbackStringToObjectConverter.java | 173 ++++++++++++++++++ .../conversion/StringConversionSupport.java | 123 +++++++++++++ .../conversion/StringToBooleanConverter.java | 30 +++ .../StringToCharacterConverter.java | 28 +++ .../conversion/StringToClassConverter.java | 36 ++++ .../StringToCommonJavaTypesConverter.java | 70 +++++++ .../conversion/StringToEnumConverter.java | 26 +++ .../conversion/StringToJavaTimeConverter.java | 65 +++++++ .../conversion/StringToNumberConverter.java | 50 +++++ .../conversion/StringToObjectConverter.java | 46 +++++ .../support/conversion/package-info.java | 5 + .../module-info.java | 1 + .../junit-platform-commons.expected.txt | 1 + 17 files changed, 708 insertions(+), 40 deletions(-) create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionException.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverter.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringConversionSupport.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToBooleanConverter.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCharacterConverter.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCommonJavaTypesConverter.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToEnumConverter.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToJavaTimeConverter.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToNumberConverter.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java create mode 100644 junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/package-info.java diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc index 748c0412c6ca..7f583260120f 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc @@ -25,7 +25,8 @@ JUnit repository on GitHub. ==== New Features and Improvements -* ❓ +* New `StringConversionSupport` in `junit-platform-commons` to expose + internal conversion logic used by Jupiter's `DefaultArgumentConverter` [[release-notes-5.11.0-M1-junit-jupiter]] diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java index fe697c5696e3..adbb606da691 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/DefaultArgumentConverter.java @@ -10,10 +10,7 @@ package org.junit.jupiter.params.converter; -import static java.util.Arrays.asList; -import static java.util.Collections.unmodifiableList; import static org.apiguardian.api.API.Status.INTERNAL; -import static org.junit.platform.commons.util.ReflectionUtils.getWrapperType; import java.io.File; import java.math.BigDecimal; @@ -21,13 +18,13 @@ import java.net.URI; import java.net.URL; import java.util.Currency; -import java.util.List; import java.util.Locale; -import java.util.Optional; import java.util.UUID; import org.apiguardian.api.API; import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.platform.commons.support.conversion.ConversionException; +import org.junit.platform.commons.support.conversion.StringConversionSupport; import org.junit.platform.commons.util.ClassLoaderUtils; import org.junit.platform.commons.util.ReflectionUtils; @@ -47,23 +44,13 @@ * * @since 5.0 * @see org.junit.jupiter.params.converter.ArgumentConverter + * @see org.junit.platform.commons.support.conversion.StringConversionSupport */ @API(status = INTERNAL, since = "5.0") public class DefaultArgumentConverter implements ArgumentConverter { public static final DefaultArgumentConverter INSTANCE = new DefaultArgumentConverter(); - private static final List stringToObjectConverters = unmodifiableList(asList( // - new StringToBooleanConverter(), // - new StringToCharacterConverter(), // - new StringToNumberConverter(), // - new StringToClassConverter(), // - new StringToEnumConverter(), // - new StringToJavaTimeConverter(), // - new StringToCommonJavaTypesConverter(), // - new FallbackStringToObjectConverter() // - )); - private DefaultArgumentConverter() { // nothing to initialize } @@ -88,34 +75,19 @@ public final Object convert(Object source, Class targetType, ParameterContext } if (source instanceof String) { - Class targetTypeToUse = toWrapperType(targetType); - Optional converter = stringToObjectConverters.stream().filter( - candidate -> candidate.canConvert(targetTypeToUse)).findFirst(); - if (converter.isPresent()) { - Class declaringClass = context.getDeclaringExecutable().getDeclaringClass(); - ClassLoader classLoader = ClassLoaderUtils.getClassLoader(declaringClass); - try { - return converter.get().convert((String) source, targetTypeToUse, classLoader); - } - catch (Exception ex) { - if (ex instanceof ArgumentConversionException) { - // simply rethrow it - throw (ArgumentConversionException) ex; - } - // else - throw new ArgumentConversionException( - "Failed to convert String \"" + source + "\" to type " + targetType.getTypeName(), ex); - } + Class declaringClass = context.getDeclaringExecutable().getDeclaringClass(); + ClassLoader classLoader = ClassLoaderUtils.getClassLoader(declaringClass); + try { + return StringConversionSupport.convert((String) source, targetType, classLoader); + } + catch (ConversionException ex) { + throw new ArgumentConversionException(ex.getMessage(), ex); } } + throw new ArgumentConversionException( String.format("No built-in converter for source type %s and target type %s", source.getClass().getTypeName(), targetType.getTypeName())); } - private static Class toWrapperType(Class targetType) { - Class wrapperType = getWrapperType(targetType); - return wrapperType != null ? wrapperType : targetType; - } - } diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java index 76d432b9564c..b2b1e7667722 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/DefaultArgumentConverterTests.java @@ -157,24 +157,28 @@ void throwsExceptionOnInvalidStringForPrimitiveTypes() { .isThrownBy(() -> convert("ab", char.class)) // .withMessage("Failed to convert String \"ab\" to type char") // .havingCause() // + .havingCause() // .withMessage("String must have length of 1: ab"); assertThatExceptionOfType(ArgumentConversionException.class) // .isThrownBy(() -> convert("tru", boolean.class)) // .withMessage("Failed to convert String \"tru\" to type boolean") // .havingCause() // + .havingCause() // .withMessage("String must be 'true' or 'false' (ignoring case): tru"); assertThatExceptionOfType(ArgumentConversionException.class) // .isThrownBy(() -> convert("null", boolean.class)) // .withMessage("Failed to convert String \"null\" to type boolean") // .havingCause() // + .havingCause() // .withMessage("String must be 'true' or 'false' (ignoring case): null"); assertThatExceptionOfType(ArgumentConversionException.class) // .isThrownBy(() -> convert("NULL", boolean.class)) // .withMessage("Failed to convert String \"NULL\" to type boolean") // .havingCause() // + .havingCause() // .withMessage("String must be 'true' or 'false' (ignoring case): NULL"); } diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionException.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionException.java new file mode 100644 index 000000000000..439334635776 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionException.java @@ -0,0 +1,37 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import static org.apiguardian.api.API.Status.EXPERIMENTAL; + +import org.apiguardian.api.API; +import org.junit.platform.commons.JUnitException; + +/** + * {@code ConversionException} is an exception that can occur when an + * object is converted to another object. + * + * @since 1.11 + */ +@API(status = EXPERIMENTAL, since = "1.11") +public class ConversionException extends JUnitException { + + private static final long serialVersionUID = 1L; + + public ConversionException(String message) { + super(message); + } + + public ConversionException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverter.java new file mode 100644 index 000000000000..06dc29153e31 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverter.java @@ -0,0 +1,173 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.BOTTOM_UP; +import static org.junit.platform.commons.util.ReflectionUtils.findConstructors; +import static org.junit.platform.commons.util.ReflectionUtils.findMethods; +import static org.junit.platform.commons.util.ReflectionUtils.invokeMethod; +import static org.junit.platform.commons.util.ReflectionUtils.isNotPrivate; +import static org.junit.platform.commons.util.ReflectionUtils.isNotStatic; +import static org.junit.platform.commons.util.ReflectionUtils.newInstance; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.function.Predicate; + +import org.junit.platform.commons.util.Preconditions; + +/** + * {@code FallbackStringToObjectConverter} is a {@link StringToObjectConverter} + * that provides a fallback conversion strategy for converting from a + * {@link String} to a given target type by invoking a static factory method + * or factory constructor defined in the target type. + * + *

Search Algorithm

+ * + *
    + *
  1. Search for a single, non-private static factory method in the target + * type that converts from a String to the target type. Use the factory method + * if present.
  2. + *
  3. Search for a single, non-private constructor in the target type that + * accepts a String. Use the constructor if present.
  4. + *
+ * + *

If multiple suitable factory methods are discovered they will be ignored. + * If neither a single factory method nor a single constructor is found, this + * converter acts as a no-op. + * + * @since 1.11 + * @see StringConversionSupport + */ +class FallbackStringToObjectConverter implements StringToObjectConverter { + + /** + * Implementation of the NULL Object Pattern. + */ + private static final Function NULL_EXECUTABLE = source -> source; + + /** + * Cache for factory methods and factory constructors. + * + *

Searches that do not find a factory method or constructor are tracked + * by the presence of a {@link #NULL_EXECUTABLE} object stored in the map. + * This prevents the framework from repeatedly searching for things which + * are already known not to exist. + */ + private static final ConcurrentHashMap, Function> factoryExecutableCache // + = new ConcurrentHashMap<>(64); + + @Override + public boolean canConvert(Class targetType) { + return findFactoryExecutable(targetType) != NULL_EXECUTABLE; + } + + @Override + public Object convert(String source, Class targetType) throws Exception { + Function executable = findFactoryExecutable(targetType); + Preconditions.condition(executable != NULL_EXECUTABLE, + "Illegal state: convert() must not be called if canConvert() returned false"); + + return executable.apply(source); + } + + private static Function findFactoryExecutable(Class targetType) { + return factoryExecutableCache.computeIfAbsent(targetType, type -> { + Method factoryMethod = findFactoryMethod(type); + if (factoryMethod != null) { + return source -> invokeMethod(factoryMethod, null, source); + } + Constructor constructor = findFactoryConstructor(type); + if (constructor != null) { + return source -> newInstance(constructor, source); + } + return NULL_EXECUTABLE; + }); + } + + private static Method findFactoryMethod(Class targetType) { + List factoryMethods = findMethods(targetType, new IsFactoryMethod(targetType), BOTTOM_UP); + if (factoryMethods.size() == 1) { + return factoryMethods.get(0); + } + return null; + } + + private static Constructor findFactoryConstructor(Class targetType) { + List> constructors = findConstructors(targetType, new IsFactoryConstructor(targetType)); + if (constructors.size() == 1) { + return constructors.get(0); + } + return null; + } + + /** + * {@link Predicate} that determines if the {@link Method} supplied to + * {@link #test(Method)} is a non-private static factory method for the + * supplied {@link #targetType}. + */ + static class IsFactoryMethod implements Predicate { + + private final Class targetType; + + IsFactoryMethod(Class targetType) { + this.targetType = targetType; + } + + @Override + public boolean test(Method method) { + // Please do not collapse the following into a single statement. + if (!method.getReturnType().equals(this.targetType)) { + return false; + } + if (isNotStatic(method)) { + return false; + } + return isNotPrivateAndAcceptsSingleStringArgument(method); + } + + } + + /** + * {@link Predicate} that determines if the {@link Constructor} supplied to + * {@link #test(Constructor)} is a non-private factory constructor for the + * supplied {@link #targetType}. + */ + static class IsFactoryConstructor implements Predicate> { + + private final Class targetType; + + IsFactoryConstructor(Class targetType) { + this.targetType = targetType; + } + + @Override + public boolean test(Constructor constructor) { + // Please do not collapse the following into a single statement. + if (!constructor.getDeclaringClass().equals(this.targetType)) { + return false; + } + return isNotPrivateAndAcceptsSingleStringArgument(constructor); + } + + } + + private static boolean isNotPrivateAndAcceptsSingleStringArgument(Executable executable) { + return isNotPrivate(executable) // + && (executable.getParameterCount() == 1) // + && (executable.getParameterTypes()[0] == String.class); + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringConversionSupport.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringConversionSupport.java new file mode 100644 index 000000000000..2ac35dc67461 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringConversionSupport.java @@ -0,0 +1,123 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import static java.util.Arrays.asList; +import static java.util.Collections.unmodifiableList; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; +import static org.junit.platform.commons.util.ReflectionUtils.getWrapperType; + +import java.io.File; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URI; +import java.net.URL; +import java.util.Currency; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.UUID; + +import org.apiguardian.api.API; +import org.junit.platform.commons.util.ClassLoaderUtils; + +/** + * {@code StringConversionSupport} is able to convert from strings to a number + * of primitive types and their corresponding wrapper types (Byte, Short, + * Integer, Long, Float, and Double), date and time types from the + * {@code java.time} package, and some additional common Java types such as + * {@link File}, {@link BigDecimal}, {@link BigInteger}, {@link Currency}, + * {@link Locale}, {@link URI}, {@link URL}, {@link UUID}, etc. + * + *

If the target type is {@code String} the source {@code String} will not + * be modified. + * + * @since 1.11 + */ +@API(status = EXPERIMENTAL, since = "1.11") +public final class StringConversionSupport { + + private static final List stringToObjectConverters = unmodifiableList(asList( // + new StringToBooleanConverter(), // + new StringToCharacterConverter(), // + new StringToNumberConverter(), // + new StringToClassConverter(), // + new StringToEnumConverter(), // + new StringToJavaTimeConverter(), // + new StringToCommonJavaTypesConverter(), // + new FallbackStringToObjectConverter() // + )); + + private StringConversionSupport() { + /* no-op */ + } + + /** + * Convert a {@code String} into an object of the supplied type. + * + *

Some underlying converters can require a {@code ClassLoader}. + * If none is provided, the default one given by + * {@link ClassLoaderUtils#getDefaultClassLoader()} will be used. + * + * @param source the source {@code String} to convert; may be {@code null} + * @param targetType the target type the source should be converted into; + * never {@code null} + * @param classLoader the {@code ClassLoader} to use; may be {@code null} + * @param the type of the target + * @return the converted object; may be {@code null} but only if the target + * type is a reference type + * + * @since 1.11 + */ + @SuppressWarnings("unchecked") + public static T convert(String source, Class targetType, ClassLoader classLoader) { + if (source == null) { + if (targetType.isPrimitive()) { + throw new ConversionException( + "Cannot convert null to primitive value of type " + targetType.getTypeName()); + } + return null; + } + + if (String.class.equals(targetType)) { + return (T) source; + } + + Class targetTypeToUse = toWrapperType(targetType); + Optional converter = stringToObjectConverters.stream().filter( + candidate -> candidate.canConvert(targetTypeToUse)).findFirst(); + if (converter.isPresent()) { + try { + ClassLoader classLoaderToUse = classLoader != null ? classLoader + : ClassLoaderUtils.getDefaultClassLoader(); + return (T) converter.get().convert(source, targetTypeToUse, classLoaderToUse); + } + catch (Exception ex) { + if (ex instanceof ConversionException) { + // simply rethrow it + throw (ConversionException) ex; + } + // else + throw new ConversionException( + String.format("Failed to convert String \"%s\" to type %s", source, targetType.getTypeName()), ex); + } + } + + throw new ConversionException( + "No built-in converter for source type java.lang.String and target type " + targetType.getTypeName()); + } + + private static Class toWrapperType(Class targetType) { + Class wrapperType = getWrapperType(targetType); + return wrapperType != null ? wrapperType : targetType; + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToBooleanConverter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToBooleanConverter.java new file mode 100644 index 000000000000..2bde9ac323c2 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToBooleanConverter.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import org.junit.platform.commons.util.Preconditions; + +class StringToBooleanConverter implements StringToObjectConverter { + + @Override + public boolean canConvert(Class targetType) { + return targetType == Boolean.class; + } + + @Override + public Object convert(String source, Class targetType) { + boolean isTrue = "true".equalsIgnoreCase(source); + Preconditions.condition(isTrue || "false".equalsIgnoreCase(source), + () -> "String must be 'true' or 'false' (ignoring case): " + source); + return isTrue; + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCharacterConverter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCharacterConverter.java new file mode 100644 index 000000000000..925acdfe62d5 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCharacterConverter.java @@ -0,0 +1,28 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import org.junit.platform.commons.util.Preconditions; + +class StringToCharacterConverter implements StringToObjectConverter { + + @Override + public boolean canConvert(Class targetType) { + return targetType == Character.class; + } + + @Override + public Object convert(String source, Class targetType) { + Preconditions.condition(source.length() == 1, () -> "String must have length of 1: " + source); + return source.charAt(0); + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java new file mode 100644 index 000000000000..df2b0164ad5c --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java @@ -0,0 +1,36 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import org.junit.platform.commons.util.ReflectionUtils; + +class StringToClassConverter implements StringToObjectConverter { + + @Override + public boolean canConvert(Class targetType) { + return targetType == Class.class; + } + + @Override + public Object convert(String source, Class targetType) throws Exception { + throw new UnsupportedOperationException("Invoke convert(String, Class, ClassLoader) instead"); + } + + @Override + public Object convert(String className, Class targetType, ClassLoader classLoader) throws Exception { + // @formatter:off + return ReflectionUtils.tryToLoadClass(className, classLoader) + .getOrThrow(cause -> new ConversionException( + "Failed to convert String \"" + className + "\" to type java.lang.Class", cause)); + // @formatter:on + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCommonJavaTypesConverter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCommonJavaTypesConverter.java new file mode 100644 index 000000000000..2988714318e3 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToCommonJavaTypesConverter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import static java.util.Collections.unmodifiableMap; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Currency; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; + +class StringToCommonJavaTypesConverter implements StringToObjectConverter { + + private static final Map, Function> CONVERTERS; + + static { + Map, Function> converters = new HashMap<>(); + + // java.io and java.nio + converters.put(File.class, File::new); + converters.put(Charset.class, Charset::forName); + converters.put(Path.class, Paths::get); + // java.net + converters.put(URI.class, URI::create); + converters.put(URL.class, StringToCommonJavaTypesConverter::toURL); + // java.util + converters.put(Currency.class, Currency::getInstance); + converters.put(Locale.class, Locale::new); + converters.put(UUID.class, UUID::fromString); + + CONVERTERS = unmodifiableMap(converters); + } + + @Override + public boolean canConvert(Class targetType) { + return CONVERTERS.containsKey(targetType); + } + + @Override + public Object convert(String source, Class targetType) throws Exception { + return CONVERTERS.get(targetType).apply(source); + } + + private static URL toURL(String url) { + try { + return URI.create(url).toURL(); + } + catch (MalformedURLException ex) { + throw new ConversionException("Failed to convert String \"" + url + "\" to type java.net.URL", ex); + } + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToEnumConverter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToEnumConverter.java new file mode 100644 index 000000000000..48c07fa59eb7 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToEnumConverter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +class StringToEnumConverter implements StringToObjectConverter { + + @Override + public boolean canConvert(Class targetType) { + return targetType.isEnum(); + } + + @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Object convert(String source, Class targetType) throws Exception { + return Enum.valueOf(targetType, source); + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToJavaTimeConverter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToJavaTimeConverter.java new file mode 100644 index 000000000000..6ecbf84b25e5 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToJavaTimeConverter.java @@ -0,0 +1,65 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import static java.util.Collections.unmodifiableMap; + +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Period; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +class StringToJavaTimeConverter implements StringToObjectConverter { + + private static final Map, Function> CONVERTERS; + static { + Map, Function> converters = new HashMap<>(); + converters.put(Duration.class, Duration::parse); + converters.put(Instant.class, Instant::parse); + converters.put(LocalDate.class, LocalDate::parse); + converters.put(LocalDateTime.class, LocalDateTime::parse); + converters.put(LocalTime.class, LocalTime::parse); + converters.put(MonthDay.class, MonthDay::parse); + converters.put(OffsetDateTime.class, OffsetDateTime::parse); + converters.put(OffsetTime.class, OffsetTime::parse); + converters.put(Period.class, Period::parse); + converters.put(Year.class, Year::parse); + converters.put(YearMonth.class, YearMonth::parse); + converters.put(ZonedDateTime.class, ZonedDateTime::parse); + converters.put(ZoneId.class, ZoneId::of); + converters.put(ZoneOffset.class, ZoneOffset::of); + CONVERTERS = unmodifiableMap(converters); + } + + @Override + public boolean canConvert(Class targetType) { + return CONVERTERS.containsKey(targetType); + } + + @Override + public Object convert(String source, Class targetType) throws Exception { + return CONVERTERS.get(targetType).apply(source); + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToNumberConverter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToNumberConverter.java new file mode 100644 index 000000000000..b8cd6e7d3e4f --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToNumberConverter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +import static java.util.Collections.unmodifiableMap; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +class StringToNumberConverter implements StringToObjectConverter { + + private static final Map, Function> CONVERTERS; + static { + Map, Function> converters = new HashMap<>(); + converters.put(Byte.class, Byte::decode); + converters.put(Short.class, Short::decode); + converters.put(Integer.class, Integer::decode); + converters.put(Long.class, Long::decode); + converters.put(Float.class, Float::valueOf); + converters.put(Double.class, Double::valueOf); + // Technically, BigInteger and BigDecimal constructors are covered by + // FallbackStringToObjectConverter, but we have explicit conversion + // configured for them anyway. + converters.put(BigInteger.class, BigInteger::new); + converters.put(BigDecimal.class, BigDecimal::new); + CONVERTERS = unmodifiableMap(converters); + } + + @Override + public boolean canConvert(Class targetType) { + return CONVERTERS.containsKey(targetType); + } + + @Override + public Object convert(String source, Class targetType) { + return CONVERTERS.get(targetType).apply(source.replace("_", "")); + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java new file mode 100644 index 000000000000..243bfeec4afc --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015-2023 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package org.junit.platform.commons.support.conversion; + +/** + * Internal API for converting arguments of type {@link String} to a specified + * target type. + */ +interface StringToObjectConverter { + + /** + * Determine if this converter can convert from a {@link String} to the + * supplied target type (which is guaranteed to be a wrapper type for + * primitives — for example, {@link Integer} instead of {@code int}). + */ + boolean canConvert(Class targetType); + + /** + * Convert the supplied {@link String} to the supplied target type (which is + * guaranteed to be a wrapper type for primitives — for example, + * {@link Integer} instead of {@code int}). + */ + Object convert(String source, Class targetType) throws Exception; + + /** + * Convert the supplied {@link String} to the supplied target type (which is + * guaranteed to be a wrapper type for primitives — for example, + * {@link Integer} instead of {@code int}). + * + *

The default implementation simply delegates to {@link #convert(String, Class)}. + * Can be overridden by concrete implementations of this interface that need + * access to the supplied {@link ClassLoader}. + */ + default Object convert(String source, Class targetType, ClassLoader classLoader) throws Exception { + return convert(source, targetType); + } + +} diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/package-info.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/package-info.java new file mode 100644 index 000000000000..e51977179941 --- /dev/null +++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/package-info.java @@ -0,0 +1,5 @@ +/** + * Maintained conversion APIs provided by the JUnit Platform. + */ + +package org.junit.platform.commons.support.conversion; diff --git a/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java b/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java index f33ffd314feb..774684198f9f 100644 --- a/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java +++ b/junit-platform-commons/src/module/org.junit.platform.commons/module-info.java @@ -36,6 +36,7 @@ org.junit.platform.testkit, org.junit.vintage.engine; exports org.junit.platform.commons.support; + exports org.junit.platform.commons.support.conversion; exports org.junit.platform.commons.util to org.junit.jupiter.api, org.junit.jupiter.engine, diff --git a/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt b/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt index 5c0c9b44e4ef..cb3eb72ae947 100644 --- a/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt +++ b/platform-tooling-support-tests/projects/jar-describe-module/junit-platform-commons.expected.txt @@ -3,6 +3,7 @@ exports org.junit.platform.commons exports org.junit.platform.commons.annotation exports org.junit.platform.commons.function exports org.junit.platform.commons.support +exports org.junit.platform.commons.support.conversion requires java.base mandated requires java.logging requires java.management From 863108b11ea77b48fad85794884f221161c3b579 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 17:11:22 +0000 Subject: [PATCH 114/142] Bump gradleVersionsPlugin from 0.49.0 to 0.50.0 Bumps `gradleVersionsPlugin` from 0.49.0 to 0.50.0. Updates `com.github.ben-manes:gradle-versions-plugin` from 0.49.0 to 0.50.0 - [Release notes](https://github.com/ben-manes/gradle-versions-plugin/releases) - [Commits](https://github.com/ben-manes/gradle-versions-plugin/compare/v0.49.0...v0.50.0) Updates `com.github.ben-manes.versions` from 0.49.0 to 0.50.0 --- updated-dependencies: - dependency-name: com.github.ben-manes:gradle-versions-plugin dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.github.ben-manes.versions dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8b56c252d1a7..0dc21278d675 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ asciidoctor-plugins = "4.0.0-alpha.1" # Check if workaround in documentation.gra assertj = "3.24.2" bnd = "7.0.0" checkstyle = "10.12.5" -gradleVersionsPlugin = "0.49.0" +gradleVersionsPlugin = "0.50.0" jacoco = "0.8.7" jmh = "1.37" junit4 = "4.13.2" From 4303615a393b40a51a68a2dd0285a8b1c1f460a5 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 25 Nov 2023 16:40:49 +0100 Subject: [PATCH 115/142] Polish release notes for 5.11.0-M1 --- .../release-notes/release-notes-5.11.0-M1.adoc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc index 7f583260120f..82bc47ad0e99 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc @@ -6,8 +6,8 @@ *Scope:* ❓ For a complete list of all _closed_ issues and pull requests for this release, consult the -link:{junit5-repo}+/milestone/68?closed=1+[5.11.0-M1] milestone page in the -JUnit repository on GitHub. +link:{junit5-repo}+/milestone/68?closed=1+[5.11.0-M1] milestone page in the JUnit +repository on GitHub. [[release-notes-5.11.0-M1-junit-platform]] @@ -15,8 +15,8 @@ JUnit repository on GitHub. ==== Bug Fixes -* ❓ -* Fixes use of the launcher as a Java module when `junit.platform.launcher.interceptors.enabled` is enabled +* Allow `junit-platform-launcher` to be used as a Java module when + `junit.platform.launcher.interceptors.enabled` is set to `true`. - See link:https://github.com/junit-team/junit5/issues/3561[issue 3561] for details. ==== Deprecations and Breaking Changes @@ -25,8 +25,9 @@ JUnit repository on GitHub. ==== New Features and Improvements -* New `StringConversionSupport` in `junit-platform-commons` to expose - internal conversion logic used by Jupiter's `DefaultArgumentConverter` +* New `StringConversionSupport` in `junit-platform-commons` to expose internal conversion + logic used by Jupiter's `DefaultArgumentConverter` for use in third-party extensions and + test engines. [[release-notes-5.11.0-M1-junit-jupiter]] @@ -38,7 +39,7 @@ JUnit repository on GitHub. ==== Deprecations and Breaking Changes -* Change used Kotlin API and language version from 1.3 to 1.6 +* Change used Kotlin API and language version from 1.3 to 1.6. ==== New Features and Improvements From 72b70a1033e52b66d32c0da843bc734401a5cea2 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 25 Nov 2023 16:58:16 +0100 Subject: [PATCH 116/142] Document StringConversionSupport in the User Guide Closes #3449 --- .../src/docs/asciidoc/link-attributes.adoc | 1 + .../docs/asciidoc/user-guide/extensions.adoc | 20 ++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/documentation/src/docs/asciidoc/link-attributes.adoc b/documentation/src/docs/asciidoc/link-attributes.adoc index 6aa27c3d46b8..712c8709a63f 100644 --- a/documentation/src/docs/asciidoc/link-attributes.adoc +++ b/documentation/src/docs/asciidoc/link-attributes.adoc @@ -14,6 +14,7 @@ endif::[] :ClassSupport: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/ClassSupport.html[ClassSupport] :ModifierSupport: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/ModifierSupport.html[ModifierSupport] :ReflectionSupport: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/ReflectionSupport.html[ReflectionSupport] +:StringConversionSupport: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/support/conversion/StringConversionSupport.html[StringConversionSupport] :Testable: {javadoc-root}/org.junit.platform.commons/org/junit/platform/commons/annotation/Testable.html[@Testable] // Platform Console Launcher :junit-platform-console: {javadoc-root}/org.junit.platform.console/org/junit/platform/console/package-summary.html[junit-platform-console] diff --git a/documentation/src/docs/asciidoc/user-guide/extensions.adoc b/documentation/src/docs/asciidoc/user-guide/extensions.adoc index e8a1512a5e40..48ded08a70d5 100644 --- a/documentation/src/docs/asciidoc/user-guide/extensions.adoc +++ b/documentation/src/docs/asciidoc/user-guide/extensions.adoc @@ -687,11 +687,11 @@ method in the inverse order they were added in. [[extensions-supported-utilities]] === Supported Utilities in Extensions -The `junit-platform-commons` artifact exposes a package named -`{junit-platform-support-package}` that contains _maintained_ utility methods for working -with annotations, classes, reflection, and classpath scanning tasks. `TestEngine` and -`Extension` authors are encouraged to use these supported methods in order to align with -the behavior of the JUnit Platform. +The `junit-platform-commons` artifact provides _maintained_ utilities for working with +annotations, classes, reflection, classpath scanning, and conversion tasks. These +utilities can be found in the `{junit-platform-support-package}` and its subpackages. +`TestEngine` and `Extension` authors are encouraged to use these supported utilities in +order to align with the behavior of the JUnit Platform and JUnit Jupiter. [[extensions-supported-utilities-annotations]] ==== Annotation Support @@ -728,6 +728,16 @@ modifiers -- for example, to determine if a member is declared as `public`, `pri `abstract`, `static`, etc. Consult the Javadoc for `{ModifierSupport}` for further details. +[[extensions-supported-utilities-conversion]] +==== Conversion Support + +`StringConversionSupport` (in the `org.junit.platform.commons.support.conversion` package) +provides support for converting from strings to primitive types and their corresponding +wrapper types, date and time types from the `java.time package`, and some additional +common Java types such as `File`, `BigDecimal`, `BigInteger`, `Currency`, `Locale`, `URI`, +`URL`, `UUID`, etc. Consult the Javadoc for `{StringConversionSupport}` for further +details. + [[extensions-execution-order]] === Relative Execution Order of User Code and Extensions From 40f7c178dafa7af96a118fa6fbc797c6efcb86cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 05:19:07 +0000 Subject: [PATCH 117/142] Bump github/combine-prs from 4.1.0 to 5.0.0 Bumps [github/combine-prs](https://github.com/github/combine-prs) from 4.1.0 to 5.0.0. - [Release notes](https://github.com/github/combine-prs/releases) - [Commits](https://github.com/github/combine-prs/compare/v4.1.0...v5.0.0) --- updated-dependencies: - dependency-name: github/combine-prs dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/combine-prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/combine-prs.yml b/.github/workflows/combine-prs.yml index 6ef40f908963..ce746cf22f14 100644 --- a/.github/workflows/combine-prs.yml +++ b/.github/workflows/combine-prs.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - name: combine-prs - uses: github/combine-prs@v4.1.0 + uses: github/combine-prs@v5.0.0 with: github_token: ${{ secrets.GH_TOKEN }} From 15f9decba8d95f821b2cff979a4be29fcd4fcd2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 05:45:07 +0000 Subject: [PATCH 118/142] Bump log4j from 2.21.1 to 2.22.0 Bumps `log4j` from 2.21.1 to 2.22.0. Updates `org.apache.logging.log4j:log4j-core` from 2.21.1 to 2.22.0 Updates `org.apache.logging.log4j:log4j-jul` from 2.21.1 to 2.22.0 --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.apache.logging.log4j:log4j-jul dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0dc21278d675..6fdc9179b5d4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ junit4 = "4.13.2" junit4Osgi = "4.13.2_1" junit4Min = "4.12" ktlint = "0.48.2" -log4j = "2.21.1" +log4j = "2.22.0" opentest4j = "1.3.0" openTestReporting = "0.1.0-M1" surefire = "3.2.2" From f5b78f68c6a90dfa63611c7a10027581c5d913ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 05:45:02 +0000 Subject: [PATCH 119/142] Bump com.diffplug.spotless:spotless-plugin-gradle from 6.22.0 to 6.23.0 Bumps [com.diffplug.spotless:spotless-plugin-gradle](https://github.com/diffplug/spotless) from 6.22.0 to 6.23.0. - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](https://github.com/diffplug/spotless/compare/gradle/6.22.0...gradle/6.23.0) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-plugin-gradle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6fdc9179b5d4..5ccff13f1669 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,7 +36,7 @@ gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", vers gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15.1" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } -gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.22.0" } +gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.23.0" } gradle-versions = { module = "com.github.ben-manes:gradle-versions-plugin", version.ref = "gradleVersionsPlugin" } groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.15" } groovy2-bom = { module = "org.codehaus.groovy:groovy-bom", version = "2.5.21" } From 588ad9a6dcb621da0e51b142e14b4997f6d02bb1 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Thu, 30 Nov 2023 18:30:51 +0100 Subject: [PATCH 120/142] Refer to "arguments providers" in Javadoc Closes #3579 --- .../main/java/org/junit/jupiter/params/ParameterizedTest.java | 2 +- .../java/org/junit/jupiter/params/provider/ArgumentsSource.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTest.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTest.java index 4464c67c3363..221db53a6132 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTest.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTest.java @@ -28,7 +28,7 @@ * *

Such methods must not be {@code private} or {@code static}. * - *

Argument Providers and Sources

+ *

Arguments Providers and Sources

* *

{@code @ParameterizedTest} methods must specify at least one * {@link org.junit.jupiter.params.provider.ArgumentsProvider ArgumentsProvider} diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSource.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSource.java index 04f7849d91e0..aa2eb1ced01a 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSource.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/ArgumentsSource.java @@ -23,7 +23,7 @@ /** * {@code @ArgumentsSource} is a {@linkplain Repeatable repeatable} annotation - * that is used to register {@linkplain ArgumentsProvider argument providers} + * that is used to register {@linkplain ArgumentsProvider arguments providers} * for the annotated test method. * *

{@code @ArgumentsSource} may also be used as a meta-annotation in order to From 8b36d4d7ec408fed33139ca49f0ec121e67e57b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:28:40 +0000 Subject: [PATCH 121/142] Bump org.apache.groovy:groovy from 4.0.15 to 4.0.16 Bumps [org.apache.groovy:groovy](https://github.com/apache/groovy) from 4.0.15 to 4.0.16. - [Commits](https://github.com/apache/groovy/commits) --- updated-dependencies: - dependency-name: org.apache.groovy:groovy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5ccff13f1669..6ca914b18dad 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -38,7 +38,7 @@ gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.23.0" } gradle-versions = { module = "com.github.ben-manes:gradle-versions-plugin", version.ref = "gradleVersionsPlugin" } -groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.15" } +groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.16" } groovy2-bom = { module = "org.codehaus.groovy:groovy-bom", version = "2.5.21" } hamcrest = { module = "org.hamcrest:hamcrest", version = "2.2" } jfrunit = { module = "org.moditect.jfrunit:jfrunit-core", version = "1.0.0.Alpha2" } From b8040db47ee888a2205fa1d64c9c978845f3128d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:28:50 +0000 Subject: [PATCH 122/142] Bump com.diffplug.spotless:spotless-plugin-gradle from 6.23.0 to 6.23.3 Bumps [com.diffplug.spotless:spotless-plugin-gradle](https://github.com/diffplug/spotless) from 6.23.0 to 6.23.3. - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](https://github.com/diffplug/spotless/compare/gradle/6.23.0...gradle/6.23.3) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-plugin-gradle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6ca914b18dad..e6e9bd19fd8a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,7 +36,7 @@ gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", vers gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15.1" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } -gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.23.0" } +gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.23.3" } gradle-versions = { module = "com.github.ben-manes:gradle-versions-plugin", version.ref = "gradleVersionsPlugin" } groovy4 = { module = "org.apache.groovy:groovy", version = "4.0.16" } groovy2-bom = { module = "org.codehaus.groovy:groovy-bom", version = "2.5.21" } From 2cad7acee4e316304724e8256e2e8e9466cddb40 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:28:56 +0000 Subject: [PATCH 123/142] Bump com.tngtech.archunit:archunit-junit5 from 1.2.0 to 1.2.1 Bumps [com.tngtech.archunit:archunit-junit5](https://github.com/TNG/ArchUnit) from 1.2.0 to 1.2.1. - [Release notes](https://github.com/TNG/ArchUnit/releases) - [Commits](https://github.com/TNG/ArchUnit/compare/v1.2.0...v1.2.1) --- updated-dependencies: - dependency-name: com.tngtech.archunit:archunit-junit5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e6e9bd19fd8a..a91071ab7681 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ ant = { module = "org.apache.ant:ant", version.ref = "ant" } ant-junit = { module = "org.apache.ant:ant-junit", version.ref = "ant" } ant-junitlauncher = { module = "org.apache.ant:ant-junitlauncher", version.ref = "ant" } apiguardian = { module = "org.apiguardian:apiguardian-api", version.ref = "apiguardian" } -archunit = { module = "com.tngtech.archunit:archunit-junit5", version = "1.2.0" } +archunit = { module = "com.tngtech.archunit:archunit-junit5", version = "1.2.1" } assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } From 1ab94b791aa286a56498506ce6a81f191f75190c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:29:07 +0000 Subject: [PATCH 124/142] Bump org.mockito:mockito-junit-jupiter from 5.7.0 to 5.8.0 Bumps [org.mockito:mockito-junit-jupiter](https://github.com/mockito/mockito) from 5.7.0 to 5.8.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.7.0...v5.8.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a91071ab7681..90aa0742a3c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -53,7 +53,7 @@ log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4 maven = { module = "org.apache.maven:apache-maven", version = "3.9.5" } mavenSurefirePlugin = { module = "org.apache.maven.plugins:maven-surefire-plugin", version.ref = "surefire" } memoryfilesystem = { module = "com.github.marschall:memoryfilesystem", version = "2.7.0" } -mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.7.0" } +mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.8.0" } opentest4j = { module = "org.opentest4j:opentest4j", version.ref = "opentest4j" } openTestReporting-events = { module = "org.opentest4j.reporting:open-test-reporting-events", version.ref = "openTestReporting" } openTestReporting-tooling = { module = "org.opentest4j.reporting:open-test-reporting-tooling", version.ref = "openTestReporting" } From 55afbcfbb75814d2cbea63e887e8fd1d910181c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:29:16 +0000 Subject: [PATCH 125/142] Bump org.apache.maven:apache-maven from 3.9.5 to 3.9.6 Bumps [org.apache.maven:apache-maven](https://github.com/apache/maven) from 3.9.5 to 3.9.6. - [Release notes](https://github.com/apache/maven/releases) - [Commits](https://github.com/apache/maven/compare/maven-3.9.5...maven-3.9.6) --- updated-dependencies: - dependency-name: org.apache.maven:apache-maven dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90aa0742a3c0..42e355fb384f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,7 +50,7 @@ junit4 = { module = "junit:junit", version = { require = "[4.12,)", prefer = "4. kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version = "1.7.3" } log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4j" } -maven = { module = "org.apache.maven:apache-maven", version = "3.9.5" } +maven = { module = "org.apache.maven:apache-maven", version = "3.9.6" } mavenSurefirePlugin = { module = "org.apache.maven.plugins:maven-surefire-plugin", version.ref = "surefire" } memoryfilesystem = { module = "com.github.marschall:memoryfilesystem", version = "2.7.0" } mockito = { module = "org.mockito:mockito-junit-jupiter", version = "5.8.0" } From 0162bbfdf3cadd0d2fb71478693b0aa14c1de993 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:35:13 +0000 Subject: [PATCH 126/142] Bump actions/setup-java from 3 to 4 in /.github/actions/setup-test-jdk Bumps [actions/setup-java](https://github.com/actions/setup-java) from 3 to 4. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/actions/setup-test-jdk/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-test-jdk/action.yml b/.github/actions/setup-test-jdk/action.yml index 4e8c96266c69..c9ea27fa7cd8 100644 --- a/.github/actions/setup-test-jdk/action.yml +++ b/.github/actions/setup-test-jdk/action.yml @@ -3,7 +3,7 @@ description: Sets up the JDK required to run platform-tooling-support-tests runs: using: "composite" steps: - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: temurin java-version: 8 From 58a2e5fee8956fd214bd2a53b3010963ee18fd39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 05:41:59 +0000 Subject: [PATCH 127/142] Bump actions/setup-java from 3 to 4 in /.github/actions/run-gradle Bumps [actions/setup-java](https://github.com/actions/setup-java) from 3 to 4. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-java dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/actions/run-gradle/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/run-gradle/action.yml b/.github/actions/run-gradle/action.yml index d91435a95ca5..0985dbffd9ba 100644 --- a/.github/actions/run-gradle/action.yml +++ b/.github/actions/run-gradle/action.yml @@ -8,7 +8,7 @@ inputs: runs: using: "composite" steps: - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 id: setup-gradle-jdk with: distribution: temurin From 9115e233b8d589f1082179f2de17a4698a081cc5 Mon Sep 17 00:00:00 2001 From: JUnit Team Date: Wed, 29 Nov 2023 18:04:34 +0000 Subject: [PATCH 128/142] Bump Gradle Wrapper from 8.5-rc-3 to 8.5 --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bed1ac8ff1ac..db8c3baafe34 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=7207f771dac48bfe19d5990c8f1e7e5f3d5e8b2b98e09ad9a4c484af537f86b2 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-rc-3-bin.zip +distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 4abde90c479420fa03839fa0ca588ea33562b6dc Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 9 Dec 2023 18:06:35 +0100 Subject: [PATCH 129/142] Use access key auth for remote build cache Instead of injecting user name and password for pushing to the remote build cache, the build now uses the user access key for authentication. --- .github/workflows/cross-version.yml | 2 -- .github/workflows/main.yml | 2 -- .../plugins/build-parameters/build.gradle.kts | 13 ++------ settings.gradle.kts | 31 ++++++++++--------- 4 files changed, 19 insertions(+), 29 deletions(-) diff --git a/.github/workflows/cross-version.yml b/.github/workflows/cross-version.yml index e71a1adf00dd..02baabfbbad5 100644 --- a/.github/workflows/cross-version.yml +++ b/.github/workflows/cross-version.yml @@ -11,8 +11,6 @@ on: env: ENTERPRISE_TESTDISTRIBUTION_ENABLED: true - BUILDCACHE_USERNAME: ${{ secrets.BUILD_CACHE_USERNAME }} - BUILDCACHE_PASSWORD: ${{ secrets.BUILD_CACHE_PASSWORD }} GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} jobs: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4cde61a60b1..30f5c439f970 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,8 +11,6 @@ on: env: ENTERPRISE_TESTDISTRIBUTION_ENABLED: true - BUILDCACHE_USERNAME: ${{ secrets.BUILD_CACHE_USERNAME }} - BUILDCACHE_PASSWORD: ${{ secrets.BUILD_CACHE_PASSWORD }} GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} jobs: diff --git a/gradle/plugins/build-parameters/build.gradle.kts b/gradle/plugins/build-parameters/build.gradle.kts index 49148effecb7..4641a8a41030 100644 --- a/gradle/plugins/build-parameters/build.gradle.kts +++ b/gradle/plugins/build-parameters/build.gradle.kts @@ -15,17 +15,8 @@ buildParameters { description = "Defines the Java toolchain version to use for compiling code" } group("buildCache") { - string("username") { - description = "Username to authenticate with the remote build cache" - fromEnvironment() - } - string("password") { - description = "Password to authenticate with the remote build cache" - fromEnvironment() - } - string("url") { - description = "URL to the remote build cache" - fromEnvironment() + string("server") { + description = "Remote build cache server address (protocol and hostname), e.g. https://eu-build-cache-ge.junit.org" } } group("documentation") { diff --git a/settings.gradle.kts b/settings.gradle.kts index 8ae205fbcbeb..8b4520e48f96 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -25,18 +25,20 @@ dependencyResolutionManagement { } val buildParameters = the() -val gradleEnterpriseServer = "https://ge.junit.org" +val develocityServer = "https://ge.junit.org" +val useDevelocityInstance = !gradle.startParameter.isBuildScan gradleEnterprise { + if (useDevelocityInstance) { + // Publish to scans.gradle.com when `--scan` is used explicitly + server = develocityServer + } buildScan { capture.isTaskInputFiles = true isUploadInBackground = !buildParameters.ci - publishAlways() - - // Publish to scans.gradle.com when `--scan` is used explicitly - if (!gradle.startParameter.isBuildScan) { - server = gradleEnterpriseServer + if (useDevelocityInstance) { + publishAlways() this as BuildScanExtensionWithHiddenFeatures publishIfAuthenticated() } @@ -60,14 +62,15 @@ buildCache { local { isEnabled = !buildParameters.ci } - remote { - url = uri(buildParameters.buildCache.url.getOrElse("$gradleEnterpriseServer/cache/")) - val buildCacheUsername = buildParameters.buildCache.username.orNull?.ifBlank { null } - val buildCachePassword = buildParameters.buildCache.password.orNull?.ifBlank { null } - isPush = buildParameters.ci && buildCacheUsername != null && buildCachePassword != null - credentials { - username = buildCacheUsername - password = buildCachePassword + if (useDevelocityInstance) { + remote(gradleEnterprise.buildCache) { + server = buildParameters.buildCache.server.orNull + val authenticated = System.getenv("GRADLE_ENTERPRISE_ACCESS_KEY") != null + isPush = buildParameters.ci && authenticated + } + } else { + remote { + url = uri(buildParameters.buildCache.server.getOrElse(develocityServer)).resolve("/cache/") } } } From f6c6637d6b2a95ad3de02f4c5c45fed4cd3f9586 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 9 Dec 2023 18:17:01 +0100 Subject: [PATCH 130/142] Rename build parameter group from "enterprise" to "develocity" --- .github/actions/run-gradle/action.yml | 2 +- .github/workflows/cross-version.yml | 2 +- .github/workflows/main.yml | 2 +- gradle/plugins/build-parameters/build.gradle.kts | 2 +- .../main/kotlin/junitbuild.testing-conventions.gradle.kts | 8 ++++---- settings.gradle.kts | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/actions/run-gradle/action.yml b/.github/actions/run-gradle/action.yml index 0985dbffd9ba..292ef6020173 100644 --- a/.github/actions/run-gradle/action.yml +++ b/.github/actions/run-gradle/action.yml @@ -19,7 +19,7 @@ runs: with: arguments: | -Porg.gradle.java.installations.auto-download=false - -Penterprise.predictiveTestSelection.enabled=${{ github.event_name == 'pull_request' }} + -Pdevelocity.predictiveTestSelection.enabled=${{ github.event_name == 'pull_request' }} "-Dscan.value.GitHub job=${{ github.job }}" javaToolchains ${{ inputs.arguments }} diff --git a/.github/workflows/cross-version.yml b/.github/workflows/cross-version.yml index 02baabfbbad5..0c97ce9e0323 100644 --- a/.github/workflows/cross-version.yml +++ b/.github/workflows/cross-version.yml @@ -10,7 +10,7 @@ on: - '*' env: - ENTERPRISE_TESTDISTRIBUTION_ENABLED: true + DEVELOCITY_TESTDISTRIBUTION_ENABLED: true GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} jobs: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 30f5c439f970..11d79586df5a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,7 +10,7 @@ on: - '*' env: - ENTERPRISE_TESTDISTRIBUTION_ENABLED: true + DEVELOCITY_TESTDISTRIBUTION_ENABLED: true GRADLE_ENTERPRISE_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_ACCESS_KEY }} jobs: diff --git a/gradle/plugins/build-parameters/build.gradle.kts b/gradle/plugins/build-parameters/build.gradle.kts index 4641a8a41030..25e16d2e5a61 100644 --- a/gradle/plugins/build-parameters/build.gradle.kts +++ b/gradle/plugins/build-parameters/build.gradle.kts @@ -26,7 +26,7 @@ buildParameters { defaultValue = false } } - group("enterprise") { + group("develocity") { description = "Parameters controlling Gradle Enterprise features" group("predictiveTestSelection") { bool("enabled") { diff --git a/gradle/plugins/common/src/main/kotlin/junitbuild.testing-conventions.gradle.kts b/gradle/plugins/common/src/main/kotlin/junitbuild.testing-conventions.gradle.kts index 086e1e6135af..e0edfb317eff 100644 --- a/gradle/plugins/common/src/main/kotlin/junitbuild.testing-conventions.gradle.kts +++ b/gradle/plugins/common/src/main/kotlin/junitbuild.testing-conventions.gradle.kts @@ -22,9 +22,9 @@ tasks.withType().configureEach { maxRetries = buildParameters.testing.retries.orElse(if (buildParameters.ci) 2 else 0) } distribution { - enabled.convention(buildParameters.enterprise.testDistribution.enabled && (!buildParameters.ci || System.getenv("GRADLE_ENTERPRISE_ACCESS_KEY").isNotBlank())) - maxLocalExecutors = buildParameters.enterprise.testDistribution.maxLocalExecutors - maxRemoteExecutors = buildParameters.enterprise.testDistribution.maxRemoteExecutors + enabled.convention(buildParameters.develocity.testDistribution.enabled && (!buildParameters.ci || System.getenv("GRADLE_ENTERPRISE_ACCESS_KEY").isNotBlank())) + maxLocalExecutors = buildParameters.develocity.testDistribution.maxLocalExecutors + maxRemoteExecutors = buildParameters.develocity.testDistribution.maxRemoteExecutors if (buildParameters.ci) { when { OperatingSystem.current().isLinux -> requirements.add("os=linux") @@ -34,7 +34,7 @@ tasks.withType().configureEach { } } predictiveSelection { - enabled = buildParameters.enterprise.predictiveTestSelection.enabled + enabled = buildParameters.develocity.predictiveTestSelection.enabled // Ensure PTS works when publishing Build Scans to scans.gradle.com this as PredictiveTestSelectionExtensionInternal diff --git a/settings.gradle.kts b/settings.gradle.kts index 8b4520e48f96..25bb18fd4d02 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -52,7 +52,7 @@ gradleEnterprise { } } - if (buildParameters.enterprise.testDistribution.enabled) { + if (buildParameters.develocity.testDistribution.enabled) { tag("test-distribution") } } From fe4b509379d5fa4805602dbb800027aaa1c0a1b7 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 9 Dec 2023 18:20:34 +0100 Subject: [PATCH 131/142] Use develocity-testing-annotations --- gradle/libs.versions.toml | 2 +- .../platform/tooling/support/tests/GraalVmStarterTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 42e355fb384f..98e2e8a15b26 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -63,7 +63,7 @@ spock1 = { module = "org.spockframework:spock-core", version = "1.3-groovy-2.5" univocity-parsers = { module = "com.univocity:univocity-parsers", version = "2.9.1" } xmlunit-assertj = { module = "org.xmlunit:xmlunit-assertj3", version.ref = "xmlunit" } xmlunit-placeholders = { module = "org.xmlunit:xmlunit-placeholders", version.ref = "xmlunit" } -testingAnnotations = { module = "com.gradle:gradle-enterprise-testing-annotations", version = "1.1.2" } +testingAnnotations = { module = "com.gradle:develocity-testing-annotations", version = "2.0" } # Only declared here so Dependabot knows when to update the referenced versions asciidoctorj-pdf = { module = "org.asciidoctor:asciidoctorj-pdf", version.ref = "asciidoctorj-pdf" } diff --git a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java index 53b5742aa4ee..0a2ab12f778a 100644 --- a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java +++ b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java @@ -21,7 +21,7 @@ import de.sormuras.bartholdy.tool.GradleWrapper; -import com.gradle.enterprise.testing.annotations.LocalOnly; +import com.gradle.develocity.testing.annotations.LocalOnly; import org.junit.jupiter.api.Test; From 15d94adf70af88d01c06bed8accb7409dc03d2ab Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 9 Dec 2023 18:58:42 +0100 Subject: [PATCH 132/142] Disable test on JDK 22 and later for now --- .../open/xml/OpenTestReportGeneratingListenerTests.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java b/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java index 99398dbc31e8..e0abc5fd55e5 100644 --- a/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java @@ -13,6 +13,7 @@ import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.condition.JRE.JAVA_22; import static org.junit.jupiter.api.io.CleanupMode.ON_SUCCESS; import static org.junit.platform.engine.discovery.DiscoverySelectors.selectUniqueId; import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request; @@ -26,6 +27,7 @@ import java.nio.file.Path; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledForJreRange; import org.junit.jupiter.api.io.TempDir; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.UniqueId; @@ -41,6 +43,7 @@ * * @since 1.9 */ +@DisabledForJreRange(min = JAVA_22, disabledReason = "https://github.com/junit-team/junit5/issues/3594") public class OpenTestReportGeneratingListenerTests { @TempDir(cleanup = ON_SUCCESS) From 2efd1c5d5d9a2d4f6e62afa7dde8dd224cfe5f9c Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 9 Dec 2023 19:02:43 +0100 Subject: [PATCH 133/142] Update Gradle Enterprise plugin to 3.16 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 98e2e8a15b26..a85bf7aae837 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -33,7 +33,7 @@ classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.165" } commons-io = { module = "commons-io:commons-io", version = "2.15.0" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.12" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } -gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.15.1" } +gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.16" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } gradle-shadow = { module = "com.github.johnrengelman:shadow", version = "8.1.1" } gradle-spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version = "6.23.3" } From c8b985d64b7478afb4bded2eaeb2ef0056f70d95 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 05:41:07 +0000 Subject: [PATCH 134/142] Bump com.gradle:common-custom-user-data-gradle-plugin Bumps com.gradle:common-custom-user-data-gradle-plugin from 1.12 to 1.12.1. --- updated-dependencies: - dependency-name: com.gradle:common-custom-user-data-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a85bf7aae837..90fd99747d88 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.165" } commons-io = { module = "commons-io:commons-io", version = "2.15.0" } -gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.12" } +gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.12.1" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.16" } gradle-bnd = { module = "biz.aQute.bnd:biz.aQute.bnd.gradle", version.ref = "bnd" } From 4e34574198373cc9415af14b05161be404191daf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 05:42:04 +0000 Subject: [PATCH 135/142] Bump actions/stale from 8 to 9 Bumps [actions/stale](https://github.com/actions/stale) from 8 to 9. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v8...v9) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/close-inactive-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/close-inactive-issues.yml b/.github/workflows/close-inactive-issues.yml index ab8bb97a6f28..fef88e94d267 100644 --- a/.github/workflows/close-inactive-issues.yml +++ b/.github/workflows/close-inactive-issues.yml @@ -10,7 +10,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@v8 + - uses: actions/stale@v9 with: only-labels: "status: waiting-for-feedback" days-before-stale: 14 From af74b89e7d448b64090c6cacfe3bebb624ac2b99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 06:52:30 +0000 Subject: [PATCH 136/142] Bump commons-io:commons-io from 2.15.0 to 2.15.1 (#3596) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90fd99747d88..6169a750abe2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ bartholdy = { module = "de.sormuras:bartholdy", version = "0.2.3" } bndlib = { module = "biz.aQute.bnd:biz.aQute.bndlib", version.ref = "bnd" } checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" } classgraph = { module = "io.github.classgraph:classgraph", version = "4.8.165" } -commons-io = { module = "commons-io:commons-io", version = "2.15.0" } +commons-io = { module = "commons-io:commons-io", version = "2.15.1" } gradle-commonCustomUserData = { module = "com.gradle:common-custom-user-data-gradle-plugin", version = "1.12.1" } gradle-foojayResolver = { module = "org.gradle.toolchains:foojay-resolver", version = "0.7.0" } gradle-enterprise = { module = "com.gradle:gradle-enterprise-gradle-plugin", version = "3.16" } From c501832e606694cc93421c1ce40416b53c62cabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonard=20Br=C3=BCnings?= Date: Fri, 15 Dec 2023 09:51:11 +0100 Subject: [PATCH 137/142] Improve error message for Store requiredType mismatch (#3601) Prior to this commit, the error message just contained the key and the requiredType, but gave no indication what was actually present. Now, the error message also includes the type of the actual value as well as its toString() representation. --- .../asciidoc/release-notes/release-notes-5.11.0-M1.adoc | 2 +- .../support/store/NamespacedHierarchicalStore.java | 3 ++- .../support/store/NamespacedHierarchicalStoreTests.java | 9 ++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc index 82bc47ad0e99..f44758f1fd5e 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc @@ -28,7 +28,7 @@ repository on GitHub. * New `StringConversionSupport` in `junit-platform-commons` to expose internal conversion logic used by Jupiter's `DefaultArgumentConverter` for use in third-party extensions and test engines. - +* Improve type mismatch error message in `NamespacedHierarchicalStore` to include actual type and value. [[release-notes-5.11.0-M1-junit-jupiter]] === JUnit Jupiter diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java index 536c029b10a0..b5e0ae725ffa 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java @@ -252,7 +252,8 @@ private T castToRequiredType(Object key, Object value, Class requiredType } // else throw new NamespacedHierarchicalStoreException( - String.format("Object stored under key [%s] is not of required type [%s]", key, requiredType.getName())); + String.format("Object stored under key [%s] is not of required type [%s], but was [%s]: %s", key, + requiredType.getName(), value.getClass(), value)); } private static class CompositeKey { diff --git a/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java b/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java index 966c8a9f4e65..c77025fcbf71 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java @@ -171,7 +171,8 @@ void getWithTypeSafetyAndInvalidRequiredTypeThrowsException() { Exception exception = assertThrows(NamespacedHierarchicalStoreException.class, () -> store.get(namespace, key, Number.class)); - assertEquals("Object stored under key [42] is not of required type [java.lang.Number]", + assertEquals( + "Object stored under key [42] is not of required type [java.lang.Number], but was [class java.lang.String]: enigma", exception.getMessage()); } @@ -221,7 +222,8 @@ void getOrComputeIfAbsentWithTypeSafetyAndInvalidRequiredTypeThrowsException() { Exception exception = assertThrows(NamespacedHierarchicalStoreException.class, () -> store.getOrComputeIfAbsent(namespace, key, defaultCreator, String.class)); - assertEquals("Object stored under key [pi] is not of required type [java.lang.String]", + assertEquals( + "Object stored under key [pi] is not of required type [java.lang.String], but was [class java.lang.Float]: 3.14", exception.getMessage()); } @@ -264,7 +266,8 @@ void removeWithTypeSafetyAndInvalidRequiredTypeThrowsException() { Exception exception = assertThrows(NamespacedHierarchicalStoreException.class, () -> store.remove(namespace, key, Number.class)); - assertEquals("Object stored under key [42] is not of required type [java.lang.Number]", + assertEquals( + "Object stored under key [42] is not of required type [java.lang.Number], but was [class java.lang.String]: enigma", exception.getMessage()); } From d254430a48e2d16e8e82cfd8ba4239281b5922e0 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Fri, 15 Dec 2023 10:11:16 +0100 Subject: [PATCH 138/142] Polish contribution See #3601 --- .../asciidoc/release-notes/release-notes-5.11.0-M1.adoc | 4 +++- .../engine/support/store/NamespacedHierarchicalStore.java | 2 +- .../support/store/NamespacedHierarchicalStoreTests.java | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc index f44758f1fd5e..49a86d6c3abb 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M1.adoc @@ -28,7 +28,9 @@ repository on GitHub. * New `StringConversionSupport` in `junit-platform-commons` to expose internal conversion logic used by Jupiter's `DefaultArgumentConverter` for use in third-party extensions and test engines. -* Improve type mismatch error message in `NamespacedHierarchicalStore` to include actual type and value. +* Error messages for type mismatches in `NamespacedHierarchicalStore` now include the + actual type and value in addition to the required type. + [[release-notes-5.11.0-M1-junit-jupiter]] === JUnit Jupiter diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java index b5e0ae725ffa..2cc1af6211c9 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java @@ -253,7 +253,7 @@ private T castToRequiredType(Object key, Object value, Class requiredType // else throw new NamespacedHierarchicalStoreException( String.format("Object stored under key [%s] is not of required type [%s], but was [%s]: %s", key, - requiredType.getName(), value.getClass(), value)); + requiredType.getName(), value.getClass().getName(), value)); } private static class CompositeKey { diff --git a/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java b/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java index c77025fcbf71..c71c625ea1c7 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStoreTests.java @@ -172,7 +172,7 @@ void getWithTypeSafetyAndInvalidRequiredTypeThrowsException() { Exception exception = assertThrows(NamespacedHierarchicalStoreException.class, () -> store.get(namespace, key, Number.class)); assertEquals( - "Object stored under key [42] is not of required type [java.lang.Number], but was [class java.lang.String]: enigma", + "Object stored under key [42] is not of required type [java.lang.Number], but was [java.lang.String]: enigma", exception.getMessage()); } @@ -223,7 +223,7 @@ void getOrComputeIfAbsentWithTypeSafetyAndInvalidRequiredTypeThrowsException() { Exception exception = assertThrows(NamespacedHierarchicalStoreException.class, () -> store.getOrComputeIfAbsent(namespace, key, defaultCreator, String.class)); assertEquals( - "Object stored under key [pi] is not of required type [java.lang.String], but was [class java.lang.Float]: 3.14", + "Object stored under key [pi] is not of required type [java.lang.String], but was [java.lang.Float]: 3.14", exception.getMessage()); } @@ -267,7 +267,7 @@ void removeWithTypeSafetyAndInvalidRequiredTypeThrowsException() { Exception exception = assertThrows(NamespacedHierarchicalStoreException.class, () -> store.remove(namespace, key, Number.class)); assertEquals( - "Object stored under key [42] is not of required type [java.lang.Number], but was [class java.lang.String]: enigma", + "Object stored under key [42] is not of required type [java.lang.Number], but was [java.lang.String]: enigma", exception.getMessage()); } From c5fbd038bde7bfa04c3beae062926ea146448ff4 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Fri, 15 Dec 2023 09:57:23 +0100 Subject: [PATCH 139/142] Submit GitHub dependency graph from main CI build see https://github.com/gradle/gradle-build-action#github-dependency-graph-support --- .github/actions/main-build/action.yml | 5 +++++ .github/actions/run-gradle/action.yml | 5 +++++ .github/workflows/main.yml | 1 + 3 files changed, 11 insertions(+) diff --git a/.github/actions/main-build/action.yml b/.github/actions/main-build/action.yml index a7817cd314f0..bdadfb3a5b90 100644 --- a/.github/actions/main-build/action.yml +++ b/.github/actions/main-build/action.yml @@ -5,6 +5,10 @@ inputs: required: true description: Gradle arguments default: build + dependency-graph: + required: false + description: 'see https://github.com/gradle/gradle-build-action#enable-dependency-graph-generation-for-a-workflow' + default: disabled runs: using: "composite" steps: @@ -12,6 +16,7 @@ runs: - uses: ./.github/actions/run-gradle with: arguments: ${{ inputs.arguments }} + dependency-graph: ${{ inputs.dependency-graph }} - uses: actions/upload-artifact@v3 if: ${{ always() }} with: diff --git a/.github/actions/run-gradle/action.yml b/.github/actions/run-gradle/action.yml index 292ef6020173..70b1cf718086 100644 --- a/.github/actions/run-gradle/action.yml +++ b/.github/actions/run-gradle/action.yml @@ -5,6 +5,10 @@ inputs: required: true description: Gradle arguments default: build + dependency-graph: + required: false + description: 'see https://github.com/gradle/gradle-build-action#enable-dependency-graph-generation-for-a-workflow' + default: disabled runs: using: "composite" steps: @@ -17,6 +21,7 @@ runs: env: JAVA_HOME: ${{ steps.setup-gradle-jdk.outputs.path }} with: + dependency-graph: ${{ inputs.dependency-graph }} arguments: | -Porg.gradle.java.installations.auto-download=false -Pdevelocity.predictiveTestSelection.enabled=${{ github.event_name == 'pull_request' }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 11d79586df5a..82b17af92f9d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,6 +35,7 @@ jobs: - name: Build uses: ./.github/actions/main-build with: + dependency-graph: generate-and-submit arguments: | -Ptesting.enableJaCoCo build From ce5f9dc0fefefc19c367260c86b742dcae555a2c Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Fri, 15 Dec 2023 10:47:16 +0100 Subject: [PATCH 140/142] Remove non-existent classpath entries for Eclipse --- .../kotlin/junitbuild.java-library-conventions.gradle.kts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gradle/plugins/common/src/main/kotlin/junitbuild.java-library-conventions.gradle.kts b/gradle/plugins/common/src/main/kotlin/junitbuild.java-library-conventions.gradle.kts index 6eb7eb308ec8..5a18f0cc4b3d 100644 --- a/gradle/plugins/common/src/main/kotlin/junitbuild.java-library-conventions.gradle.kts +++ b/gradle/plugins/common/src/main/kotlin/junitbuild.java-library-conventions.gradle.kts @@ -2,6 +2,8 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import junitbuild.java.ModuleCompileOptions import junitbuild.java.ModulePathArgumentProvider import junitbuild.java.PatchModuleArgumentProvider +import org.gradle.plugins.ide.eclipse.model.Classpath +import org.gradle.plugins.ide.eclipse.model.Library plugins { `java-library` @@ -36,6 +38,12 @@ eclipse { } } } + classpath.file.whenMerged { + this as Classpath + // Remove classpath entries for non-existent libraries added by various + // plugins, such as "junit-jupiter-api/build/classes/kotlin/testFixtures". + entries.removeIf { it is Library && !file(it.path).exists() } + } } java { From 7437348ba1535dd7ed49ef6e64fafba8e5fa118a Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Fri, 15 Dec 2023 11:02:04 +0100 Subject: [PATCH 141/142] Complete the introduction of `StringConversionSupport` This commit picks up where commit 30dbf58c77 left off. Specifically, this commit removes all obsolete StringToObjectConverter implementations from junit-jupiter-params since they now reside in junit-platform-commons. In addition, this commit moves FallbackStringToObjectConverterTests to the platform-tests module. See #3507 --- .../FallbackStringToObjectConverter.java | 173 ------------------ .../converter/StringToBooleanConverter.java | 30 --- .../converter/StringToCharacterConverter.java | 28 --- .../converter/StringToClassConverter.java | 36 ---- .../StringToCommonJavaTypesConverter.java | 70 ------- .../converter/StringToEnumConverter.java | 26 --- .../converter/StringToJavaTimeConverter.java | 65 ------- .../converter/StringToNumberConverter.java | 50 ----- .../converter/StringToObjectConverter.java | 46 ----- .../FallbackStringToObjectConverterTests.java | 8 +- 10 files changed, 4 insertions(+), 528 deletions(-) delete mode 100644 junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/FallbackStringToObjectConverter.java delete mode 100644 junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToBooleanConverter.java delete mode 100644 junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToCharacterConverter.java delete mode 100644 junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToClassConverter.java delete mode 100644 junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToCommonJavaTypesConverter.java delete mode 100644 junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToEnumConverter.java delete mode 100644 junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToJavaTimeConverter.java delete mode 100644 junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToNumberConverter.java delete mode 100644 junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToObjectConverter.java rename {junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter => platform-tests/src/test/java/org/junit/platform/commons/support/conversion}/FallbackStringToObjectConverterTests.java (95%) diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/FallbackStringToObjectConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/FallbackStringToObjectConverter.java deleted file mode 100644 index 79f0028e58a6..000000000000 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/FallbackStringToObjectConverter.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2015-2023 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params.converter; - -import static org.junit.platform.commons.util.ReflectionUtils.HierarchyTraversalMode.BOTTOM_UP; -import static org.junit.platform.commons.util.ReflectionUtils.findConstructors; -import static org.junit.platform.commons.util.ReflectionUtils.findMethods; -import static org.junit.platform.commons.util.ReflectionUtils.invokeMethod; -import static org.junit.platform.commons.util.ReflectionUtils.isNotPrivate; -import static org.junit.platform.commons.util.ReflectionUtils.isNotStatic; -import static org.junit.platform.commons.util.ReflectionUtils.newInstance; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Method; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.function.Predicate; - -import org.junit.platform.commons.util.Preconditions; - -/** - * {@code FallbackStringToObjectConverter} is a {@link StringToObjectConverter} - * that provides a fallback conversion strategy for converting from a - * {@link String} to a given target type by invoking a static factory method - * or factory constructor defined in the target type. - * - *

Search Algorithm

- * - *
    - *
  1. Search for a single, non-private static factory method in the target - * type that converts from a String to the target type. Use the factory method - * if present.
  2. - *
  3. Search for a single, non-private constructor in the target type that - * accepts a String. Use the constructor if present.
  4. - *
- * - *

If multiple suitable factory methods are discovered they will be ignored. - * If neither a single factory method nor a single constructor is found, this - * converter acts as a no-op. - * - * @since 5.1 - * @see DefaultArgumentConverter - */ -class FallbackStringToObjectConverter implements StringToObjectConverter { - - /** - * Implementation of the NULL Object Pattern. - */ - private static final Function NULL_EXECUTABLE = source -> source; - - /** - * Cache for factory methods and factory constructors. - * - *

Searches that do not find a factory method or constructor are tracked - * by the presence of a {@link #NULL_EXECUTABLE} object stored in the map. - * This prevents the framework from repeatedly searching for things which - * are already known not to exist. - */ - private static final ConcurrentHashMap, Function> factoryExecutableCache // - = new ConcurrentHashMap<>(64); - - @Override - public boolean canConvert(Class targetType) { - return findFactoryExecutable(targetType) != NULL_EXECUTABLE; - } - - @Override - public Object convert(String source, Class targetType) throws Exception { - Function executable = findFactoryExecutable(targetType); - Preconditions.condition(executable != NULL_EXECUTABLE, - "Illegal state: convert() must not be called if canConvert() returned false"); - - return executable.apply(source); - } - - private static Function findFactoryExecutable(Class targetType) { - return factoryExecutableCache.computeIfAbsent(targetType, type -> { - Method factoryMethod = findFactoryMethod(type); - if (factoryMethod != null) { - return source -> invokeMethod(factoryMethod, null, source); - } - Constructor constructor = findFactoryConstructor(type); - if (constructor != null) { - return source -> newInstance(constructor, source); - } - return NULL_EXECUTABLE; - }); - } - - private static Method findFactoryMethod(Class targetType) { - List factoryMethods = findMethods(targetType, new IsFactoryMethod(targetType), BOTTOM_UP); - if (factoryMethods.size() == 1) { - return factoryMethods.get(0); - } - return null; - } - - private static Constructor findFactoryConstructor(Class targetType) { - List> constructors = findConstructors(targetType, new IsFactoryConstructor(targetType)); - if (constructors.size() == 1) { - return constructors.get(0); - } - return null; - } - - /** - * {@link Predicate} that determines if the {@link Method} supplied to - * {@link #test(Method)} is a non-private static factory method for the - * supplied {@link #targetType}. - */ - static class IsFactoryMethod implements Predicate { - - private final Class targetType; - - IsFactoryMethod(Class targetType) { - this.targetType = targetType; - } - - @Override - public boolean test(Method method) { - // Please do not collapse the following into a single statement. - if (!method.getReturnType().equals(this.targetType)) { - return false; - } - if (isNotStatic(method)) { - return false; - } - return isNotPrivateAndAcceptsSingleStringArgument(method); - } - - } - - /** - * {@link Predicate} that determines if the {@link Constructor} supplied to - * {@link #test(Constructor)} is a non-private factory constructor for the - * supplied {@link #targetType}. - */ - static class IsFactoryConstructor implements Predicate> { - - private final Class targetType; - - IsFactoryConstructor(Class targetType) { - this.targetType = targetType; - } - - @Override - public boolean test(Constructor constructor) { - // Please do not collapse the following into a single statement. - if (!constructor.getDeclaringClass().equals(this.targetType)) { - return false; - } - return isNotPrivateAndAcceptsSingleStringArgument(constructor); - } - - } - - private static boolean isNotPrivateAndAcceptsSingleStringArgument(Executable executable) { - return isNotPrivate(executable) // - && (executable.getParameterCount() == 1) // - && (executable.getParameterTypes()[0] == String.class); - } - -} diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToBooleanConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToBooleanConverter.java deleted file mode 100644 index 9d911825809b..000000000000 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToBooleanConverter.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2015-2023 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params.converter; - -import org.junit.platform.commons.util.Preconditions; - -class StringToBooleanConverter implements StringToObjectConverter { - - @Override - public boolean canConvert(Class targetType) { - return targetType == Boolean.class; - } - - @Override - public Object convert(String source, Class targetType) { - boolean isTrue = "true".equalsIgnoreCase(source); - Preconditions.condition(isTrue || "false".equalsIgnoreCase(source), - () -> "String must be 'true' or 'false' (ignoring case): " + source); - return isTrue; - } - -} diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToCharacterConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToCharacterConverter.java deleted file mode 100644 index b3849051e45d..000000000000 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToCharacterConverter.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2015-2023 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params.converter; - -import org.junit.platform.commons.util.Preconditions; - -class StringToCharacterConverter implements StringToObjectConverter { - - @Override - public boolean canConvert(Class targetType) { - return targetType == Character.class; - } - - @Override - public Object convert(String source, Class targetType) { - Preconditions.condition(source.length() == 1, () -> "String must have length of 1: " + source); - return source.charAt(0); - } - -} diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToClassConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToClassConverter.java deleted file mode 100644 index debefc342ed0..000000000000 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToClassConverter.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2015-2023 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params.converter; - -import org.junit.platform.commons.util.ReflectionUtils; - -class StringToClassConverter implements StringToObjectConverter { - - @Override - public boolean canConvert(Class targetType) { - return targetType == Class.class; - } - - @Override - public Object convert(String source, Class targetType) throws Exception { - throw new UnsupportedOperationException("Invoke convert(String, Class, ClassLoader) instead"); - } - - @Override - public Object convert(String className, Class targetType, ClassLoader classLoader) throws Exception { - // @formatter:off - return ReflectionUtils.tryToLoadClass(className, classLoader) - .getOrThrow(cause -> new ArgumentConversionException( - "Failed to convert String \"" + className + "\" to type java.lang.Class", cause)); - // @formatter:on - } - -} diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToCommonJavaTypesConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToCommonJavaTypesConverter.java deleted file mode 100644 index b9ac124aded8..000000000000 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToCommonJavaTypesConverter.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2015-2023 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params.converter; - -import static java.util.Collections.unmodifiableMap; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Currency; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.UUID; -import java.util.function.Function; - -class StringToCommonJavaTypesConverter implements StringToObjectConverter { - - private static final Map, Function> CONVERTERS; - - static { - Map, Function> converters = new HashMap<>(); - - // java.io and java.nio - converters.put(File.class, File::new); - converters.put(Charset.class, Charset::forName); - converters.put(Path.class, Paths::get); - // java.net - converters.put(URI.class, URI::create); - converters.put(URL.class, StringToCommonJavaTypesConverter::toURL); - // java.util - converters.put(Currency.class, Currency::getInstance); - converters.put(Locale.class, Locale::new); - converters.put(UUID.class, UUID::fromString); - - CONVERTERS = unmodifiableMap(converters); - } - - @Override - public boolean canConvert(Class targetType) { - return CONVERTERS.containsKey(targetType); - } - - @Override - public Object convert(String source, Class targetType) throws Exception { - return CONVERTERS.get(targetType).apply(source); - } - - private static URL toURL(String url) { - try { - return URI.create(url).toURL(); - } - catch (MalformedURLException ex) { - throw new ArgumentConversionException("Failed to convert String \"" + url + "\" to type java.net.URL", ex); - } - } - -} diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToEnumConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToEnumConverter.java deleted file mode 100644 index f20d1487d5ee..000000000000 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToEnumConverter.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2015-2023 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params.converter; - -class StringToEnumConverter implements StringToObjectConverter { - - @Override - public boolean canConvert(Class targetType) { - return targetType.isEnum(); - } - - @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Object convert(String source, Class targetType) throws Exception { - return Enum.valueOf(targetType, source); - } - -} diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToJavaTimeConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToJavaTimeConverter.java deleted file mode 100644 index b1851ecc323d..000000000000 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToJavaTimeConverter.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2015-2023 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params.converter; - -import static java.util.Collections.unmodifiableMap; - -import java.time.Duration; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.MonthDay; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.Period; -import java.time.Year; -import java.time.YearMonth; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -class StringToJavaTimeConverter implements StringToObjectConverter { - - private static final Map, Function> CONVERTERS; - static { - Map, Function> converters = new HashMap<>(); - converters.put(Duration.class, Duration::parse); - converters.put(Instant.class, Instant::parse); - converters.put(LocalDate.class, LocalDate::parse); - converters.put(LocalDateTime.class, LocalDateTime::parse); - converters.put(LocalTime.class, LocalTime::parse); - converters.put(MonthDay.class, MonthDay::parse); - converters.put(OffsetDateTime.class, OffsetDateTime::parse); - converters.put(OffsetTime.class, OffsetTime::parse); - converters.put(Period.class, Period::parse); - converters.put(Year.class, Year::parse); - converters.put(YearMonth.class, YearMonth::parse); - converters.put(ZonedDateTime.class, ZonedDateTime::parse); - converters.put(ZoneId.class, ZoneId::of); - converters.put(ZoneOffset.class, ZoneOffset::of); - CONVERTERS = unmodifiableMap(converters); - } - - @Override - public boolean canConvert(Class targetType) { - return CONVERTERS.containsKey(targetType); - } - - @Override - public Object convert(String source, Class targetType) throws Exception { - return CONVERTERS.get(targetType).apply(source); - } - -} diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToNumberConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToNumberConverter.java deleted file mode 100644 index ca278019a488..000000000000 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToNumberConverter.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2015-2023 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params.converter; - -import static java.util.Collections.unmodifiableMap; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -class StringToNumberConverter implements StringToObjectConverter { - - private static final Map, Function> CONVERTERS; - static { - Map, Function> converters = new HashMap<>(); - converters.put(Byte.class, Byte::decode); - converters.put(Short.class, Short::decode); - converters.put(Integer.class, Integer::decode); - converters.put(Long.class, Long::decode); - converters.put(Float.class, Float::valueOf); - converters.put(Double.class, Double::valueOf); - // Technically, BigInteger and BigDecimal constructors are covered by - // FallbackStringToObjectConverter, but we have explicit conversion - // configured for them anyway. - converters.put(BigInteger.class, BigInteger::new); - converters.put(BigDecimal.class, BigDecimal::new); - CONVERTERS = unmodifiableMap(converters); - } - - @Override - public boolean canConvert(Class targetType) { - return CONVERTERS.containsKey(targetType); - } - - @Override - public Object convert(String source, Class targetType) { - return CONVERTERS.get(targetType).apply(source.replace("_", "")); - } - -} diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToObjectConverter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToObjectConverter.java deleted file mode 100644 index 2a60202dba81..000000000000 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/StringToObjectConverter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2015-2023 the original author or authors. - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v2.0 which - * accompanies this distribution and is available at - * - * https://www.eclipse.org/legal/epl-v20.html - */ - -package org.junit.jupiter.params.converter; - -/** - * Internal API for converting arguments of type {@link String} to a specified - * target type. - */ -interface StringToObjectConverter { - - /** - * Determine if this converter can convert from a {@link String} to the - * supplied target type (which is guaranteed to be a wrapper type for - * primitives — for example, {@link Integer} instead of {@code int}). - */ - boolean canConvert(Class targetType); - - /** - * Convert the supplied {@link String} to the supplied target type (which is - * guaranteed to be a wrapper type for primitives — for example, - * {@link Integer} instead of {@code int}). - */ - Object convert(String source, Class targetType) throws Exception; - - /** - * Convert the supplied {@link String} to the supplied target type (which is - * guaranteed to be a wrapper type for primitives — for example, - * {@link Integer} instead of {@code int}). - * - *

The default implementation simply delegates to {@link #convert(String, Class)}. - * Can be overridden by concrete implementations of this interface that need - * access to the supplied {@link ClassLoader}. - */ - default Object convert(String source, Class targetType, ClassLoader classLoader) throws Exception { - return convert(source, targetType); - } - -} diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/FallbackStringToObjectConverterTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverterTests.java similarity index 95% rename from junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/FallbackStringToObjectConverterTests.java rename to platform-tests/src/test/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverterTests.java index 1d2cd21a6fdf..efc98701df7d 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/FallbackStringToObjectConverterTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/conversion/FallbackStringToObjectConverterTests.java @@ -8,7 +8,7 @@ * https://www.eclipse.org/legal/epl-v20.html */ -package org.junit.jupiter.params.converter; +package org.junit.platform.commons.support.conversion; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.platform.commons.util.ReflectionUtils.findMethod; @@ -19,15 +19,15 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.converter.FallbackStringToObjectConverter.IsFactoryConstructor; -import org.junit.jupiter.params.converter.FallbackStringToObjectConverter.IsFactoryMethod; +import org.junit.platform.commons.support.conversion.FallbackStringToObjectConverter.IsFactoryConstructor; +import org.junit.platform.commons.support.conversion.FallbackStringToObjectConverter.IsFactoryMethod; import org.junit.platform.commons.util.ReflectionUtils; /** * Unit tests for {@link FallbackStringToObjectConverter}, {@link IsFactoryMethod}, * and {@link IsFactoryConstructor}. * - * @since 5.1 + * @since 1.11 (originally since JUnit Jupiter 5.1) */ class FallbackStringToObjectConverterTests { From 8f5fbd0d1693be19de86189cc6fb48394269d2d9 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Fri, 15 Dec 2023 11:13:26 +0100 Subject: [PATCH 142/142] Appease the Eclipse compiler when using Java 21 --- .../java/org/junit/platform/commons/util/CloseablePathTests.java | 1 + .../java/org/junit/platform/console/tasks/TreeNodeTests.java | 1 + 2 files changed, 2 insertions(+) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java b/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java index 395a895153ed..88a2f9acb9b3 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/util/CloseablePathTests.java @@ -73,6 +73,7 @@ void createsAndClosesJarFileSystemOnceWhenCalledConcurrently() throws Exception } @Test + @SuppressWarnings("resource") void closingIsIdempotent() throws Exception { var path1 = CloseablePath.create(uri); paths.add(path1); diff --git a/platform-tests/src/test/java/org/junit/platform/console/tasks/TreeNodeTests.java b/platform-tests/src/test/java/org/junit/platform/console/tasks/TreeNodeTests.java index d17f340c481e..35155450f90b 100644 --- a/platform-tests/src/test/java/org/junit/platform/console/tasks/TreeNodeTests.java +++ b/platform-tests/src/test/java/org/junit/platform/console/tasks/TreeNodeTests.java @@ -67,6 +67,7 @@ void reportEntriesCanBeAddedConcurrently() throws Exception { assertThat(treeNode.reports).hasSize(NUM_THREADS * ITEMS_PER_THREAD); } + @SuppressWarnings("resource") private void runConcurrently(Runnable action) throws InterruptedException { ExecutorService executor = new ThreadPoolExecutor(NUM_THREADS, NUM_THREADS, 10, SECONDS, new ArrayBlockingQueue<>(NUM_THREADS));