From fea0e5487bdebff31e7fe905492ce957a16c01bf Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Tue, 10 Jan 2023 12:32:35 +0100 Subject: [PATCH 01/25] Back to snapshots for further development --- gradle.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 627bc14582a8..2fd0518f4bd8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,13 +1,13 @@ group = org.junit -version = 5.9.2 +version = 5.9.3-SNAPSHOT jupiterGroup = org.junit.jupiter platformGroup = org.junit.platform -platformVersion = 1.9.2 +platformVersion = 1.9.3-SNAPSHOT vintageGroup = org.junit.vintage -vintageVersion = 5.9.2 +vintageVersion = 5.9.3-SNAPSHOT defaultBuiltBy = JUnit Team From b5502bf34c6d3a9131810bf76c920f53bb869ba6 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 16 Jan 2023 15:00:43 +0100 Subject: [PATCH 02/25] Fix link to JUnit 5.9.2 release (cherry picked from commit 5f268d6bea1875f9e1ce0bf1f3b9263538532197) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37241253e2d2..7b4bb98a40c3 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This repository is the home of the next generation of JUnit, _JUnit 5_. ## Latest Releases -- General Availability (GA): [JUnit 5.9.2](https://github.com/junit-team/junit5/releases/tag/r5.9.1) (January 10, 2023) +- General Availability (GA): [JUnit 5.9.2](https://github.com/junit-team/junit5/releases/tag/r5.9.2) (January 10, 2023) - Preview (Milestone/Release Candidate): n/a ## Documentation From 6c2f9c0165143793ae07590604cc8ff0139e0c51 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 28 Jan 2023 11:56:46 +0100 Subject: [PATCH 03/25] Fix tests on latest JDK 21-ea (cherry picked from commit ec2efb95f3cf8fcc03d4ac556166d6cf1ae0bcb9) --- .../platform/commons/support/ReflectionSupportTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index efa4e8105cfe..1e522ea2e4b8 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -48,7 +48,7 @@ class ReflectionSupportTests { void loadClassDelegates() { assertEquals(ReflectionUtils.loadClass("-"), ReflectionSupport.loadClass("-")); assertEquals(ReflectionUtils.loadClass("A"), ReflectionSupport.loadClass("A")); - assertEquals(ReflectionUtils.loadClass("java.io.Bits"), ReflectionSupport.loadClass("java.io.Bits")); + assertEquals(ReflectionUtils.loadClass("java.nio.Bits"), ReflectionSupport.loadClass("java.nio.Bits")); } @Test @@ -64,7 +64,7 @@ void tryToLoadClassDelegates() { ReflectionSupport.tryToLoadClass("-").toOptional()); assertEquals(ReflectionUtils.tryToLoadClass("A").toOptional(), ReflectionSupport.tryToLoadClass("A").toOptional()); - assertEquals(ReflectionUtils.tryToLoadClass("java.io.Bits"), ReflectionSupport.tryToLoadClass("java.io.Bits")); + assertEquals(ReflectionUtils.tryToLoadClass("java.nio.Bits"), ReflectionSupport.tryToLoadClass("java.nio.Bits")); } @Test From fdd0e0b17636914964875f9c677b8d4df67308f0 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 28 Jan 2023 11:58:28 +0100 Subject: [PATCH 04/25] Avoid aborting other jobs in the matrix on failure (cherry picked from commit 8e734429192c11030c597258c33d9fb834f60af8) --- .github/workflows/cross-version.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cross-version.yml b/.github/workflows/cross-version.yml index a752dcad2022..a6a6e0c3fde0 100644 --- a/.github/workflows/cross-version.yml +++ b/.github/workflows/cross-version.yml @@ -18,6 +18,7 @@ env: jobs: openjdk: strategy: + fail-fast: false matrix: jdk: [19, 20, 21] name: "OpenJDK ${{ matrix.jdk }}" From 539f33636b327fb27548781993bd02c447a142a3 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 28 Jan 2023 12:02:40 +0100 Subject: [PATCH 05/25] Fix formatting (cherry picked from commit 3c7612589c3ab198bfabf0f654092ae8b8086cac) --- .../junit/platform/commons/support/ReflectionSupportTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java index 1e522ea2e4b8..f14ff26e1fc4 100644 --- a/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java +++ b/platform-tests/src/test/java/org/junit/platform/commons/support/ReflectionSupportTests.java @@ -64,7 +64,8 @@ void tryToLoadClassDelegates() { ReflectionSupport.tryToLoadClass("-").toOptional()); assertEquals(ReflectionUtils.tryToLoadClass("A").toOptional(), ReflectionSupport.tryToLoadClass("A").toOptional()); - assertEquals(ReflectionUtils.tryToLoadClass("java.nio.Bits"), ReflectionSupport.tryToLoadClass("java.nio.Bits")); + assertEquals(ReflectionUtils.tryToLoadClass("java.nio.Bits"), + ReflectionSupport.tryToLoadClass("java.nio.Bits")); } @Test From 502810754bf7ee45cbba21087ff5a11113546dd3 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 1 Jan 2023 18:11:32 +0100 Subject: [PATCH 06/25] Update CodeQL action (cherry picked from commit 49159f24b8cc8a1956e73d2d47979726690f93bd) --- .github/workflows/codeql-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0bb949702e2d..ab55ec8760ee 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,7 @@ jobs: - name: Check out repository uses: actions/checkout@v3 - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} - name: Build @@ -35,4 +35,4 @@ jobs: -Dscan.tag.CodeQL allMainClasses - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 From fe59d74d427334d50a24231b8c8f9bf8d801acb1 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Thu, 16 Feb 2023 13:21:13 +0100 Subject: [PATCH 07/25] Disable CodeQL Java check due to Kotlin 1.8.10 not yet being supported (cherry picked from commit 1711f1c7b9fca4d269c46046624e9b5b3136e861) --- .github/workflows/codeql-analysis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ab55ec8760ee..8ef477cb6d1f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -19,7 +19,9 @@ jobs: strategy: fail-fast: false matrix: - language: ['java', 'javascript'] + language: + # - java # Currently broken because it doesn't support Kotlin 1.8.10, yet (https://github.com/github/codeql/discussions/11460#discussioncomment-4879731) + - javascript steps: - name: Check out repository uses: actions/checkout@v3 From 11e0b324aad09738afc1a6c0b109b66a2455838e Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Wed, 1 Mar 2023 20:02:33 +0100 Subject: [PATCH 08/25] Re-enable CodeQL check for Java (#3163) (cherry picked from commit ac8a5bd6c70244a0a5ba8073469452d20af3f671) --- .github/workflows/codeql-analysis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8ef477cb6d1f..222d54f252fd 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: language: - # - java # Currently broken because it doesn't support Kotlin 1.8.10, yet (https://github.com/github/codeql/discussions/11460#discussioncomment-4879731) + - java - javascript steps: - name: Check out repository @@ -29,6 +29,7 @@ jobs: uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} + tools: latest - name: Build uses: ./.github/actions/run-gradle with: From 500f098caed362ee52806179352e299ae148779e Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 16 Apr 2023 16:36:01 +0200 Subject: [PATCH 09/25] Include root cause when failing to delete file Fixes #3236. --- .../engine/extension/TempDirectory.java | 1 + .../TempDirectoryPerDeclarationTests.java | 51 +++++++++++++++++-- 2 files changed, 47 insertions(+), 5 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 ba5f53d71971..9fc7a37dc4c4 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 @@ -319,6 +319,7 @@ private void resetPermissionsAndTryToDeleteAgain(Path path, IOException exceptio } catch (Exception suppressed) { exception.addSuppressed(suppressed); + failures.put(path, exception); } } else { 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 6cc8336bb202..100bbe939499 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 @@ -29,6 +29,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; @@ -55,7 +56,6 @@ import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.extension.BeforeEachCallback; -import org.junit.jupiter.api.extension.Extension; import org.junit.jupiter.api.extension.ExtensionConfigurationException; import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.extension.RegisterExtension; @@ -200,7 +200,19 @@ void onlyAttemptsToDeleteUndeletableDirectoriesOnce() { assertSingleFailedTest(results, // instanceOf(IOException.class), // message(it -> it.startsWith("Failed to delete temp directory")), // - suppressed(0, instanceOf(IOException.class), message("Simulated failure")), // + suppressed(0, instanceOf(DirectoryNotEmptyException.class)), // + suppressed(1, instanceOf(IOException.class), message("Simulated failure"))); + } + + @Test + @DisplayName("only attempts to delete undeletable files once") + void onlyAttemptsToDeleteUndeletableFilesOnce() { + var results = executeTestsForClass(UndeletableFileTestCase.class); + + assertSingleFailedTest(results, // + instanceOf(IOException.class), // + message(it -> it.startsWith("Failed to delete temp directory")), // + suppressed(0, instanceOf(DirectoryNotEmptyException.class)), // suppressed(1, instanceOf(IOException.class), message("Simulated failure"))); } @@ -1014,16 +1026,45 @@ private static Map getTempDirs(TestInfo testInfo) { static class UndeletableDirectoryTestCase { + static final Path UNDELETABLE_SUB_DIR = Path.of("undeletable"); + @RegisterExtension - Extension injector = (BeforeEachCallback) context -> context // + BeforeEachCallback injector = context -> context // .getStore(TempDirectory.NAMESPACE) // .put(TempDirectory.FILE_OPERATIONS_KEY, (FileOperations) path -> { - throw new IOException("Simulated failure"); + if (path.endsWith(UNDELETABLE_SUB_DIR)) { + throw new IOException("Simulated failure"); + } + else { + Files.delete(path); + } }); @Test void test(@TempDir Path tempDir) throws Exception { - Files.createDirectory(tempDir.resolve("test-sub-dir")); + Files.createDirectory(tempDir.resolve(UNDELETABLE_SUB_DIR)); + } + } + + static class UndeletableFileTestCase { + + static final Path UNDELETABLE_FILE = Path.of("undeletable"); + + @RegisterExtension + BeforeEachCallback injector = context -> context // + .getStore(TempDirectory.NAMESPACE) // + .put(TempDirectory.FILE_OPERATIONS_KEY, (FileOperations) path -> { + if (path.endsWith(UNDELETABLE_FILE)) { + throw new IOException("Simulated failure"); + } + else { + Files.delete(path); + } + }); + + @Test + void test(@TempDir Path tempDir) throws Exception { + Files.createFile(tempDir.resolve(UNDELETABLE_FILE)); } } } From f6e12e04fb48adf6efaa63d2fe983dbc6f825a76 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sun, 16 Apr 2023 16:51:56 +0200 Subject: [PATCH 10/25] Improve error message when root could not be deleted (cherry picked from commit 4616b23c35ac7eb96c88f20094c481a92b5d7bd0) --- .../jupiter/engine/extension/TempDirectory.java | 12 ++++++------ .../extension/TempDirectoryPerDeclarationTests.java | 4 ++++ 2 files changed, 10 insertions(+), 6 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 9fc7a37dc4c4..624c9adbce80 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 @@ -30,6 +30,7 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.Collections; @@ -341,13 +342,12 @@ private static void resetPermissions(Path path) { } private IOException createIOExceptionWithAttachedFailures(SortedMap failures) { - // @formatter:off - String joinedPaths = failures.keySet().stream() - .map(this::tryToDeleteOnExit) - .map(this::relativizeSafely) - .map(String::valueOf) + Path emptyPath = Paths.get(""); + String joinedPaths = failures.keySet().stream() // + .map(this::tryToDeleteOnExit) // + .map(this::relativizeSafely) // + .map(path -> emptyPath.equals(path) ? "" : path.toString()) // .collect(joining(", ")); - // @formatter:on IOException exception = new IOException("Failed to delete temp directory " + dir.toAbsolutePath() + ". The following paths could not be deleted (see suppressed exceptions for details): " + joinedPaths); 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 100bbe939499..16e19ed53f71 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 @@ -200,6 +200,8 @@ void onlyAttemptsToDeleteUndeletableDirectoriesOnce() { assertSingleFailedTest(results, // instanceOf(IOException.class), // message(it -> it.startsWith("Failed to delete temp directory")), // + message(it -> it.endsWith( + "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"))); } @@ -212,6 +214,8 @@ void onlyAttemptsToDeleteUndeletableFilesOnce() { assertSingleFailedTest(results, // instanceOf(IOException.class), // message(it -> it.startsWith("Failed to delete temp directory")), // + message(it -> it.endsWith( + "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"))); } From 40bbc8ad4422832d0f3731b606d7e847c4251d28 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Mon, 17 Apr 2023 19:19:35 +0200 Subject: [PATCH 11/25] Assert absolute path is included in failure message (cherry picked from commit c9ae85af2c55e1b4748dc0348c5e5df1c4f5cd2a) --- .../TempDirectoryPerDeclarationTests.java | 78 +++++++++---------- 1 file changed, 36 insertions(+), 42 deletions(-) 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 16e19ed53f71..c98e99e0514d 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 @@ -53,6 +53,7 @@ import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.TestReporter; import org.junit.jupiter.api.condition.DisabledOnOs; import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.extension.BeforeEachCallback; @@ -63,6 +64,7 @@ import org.junit.jupiter.engine.AbstractJupiterTestEngineTests; import org.junit.jupiter.engine.Constants; import org.junit.jupiter.engine.extension.TempDirectory.FileOperations; +import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.testkit.engine.EngineExecutionResults; /** @@ -192,30 +194,26 @@ void canBeUsedViaStaticFieldInsideNestedTestClasses() { .assertStatistics(stats -> stats.started(2).succeeded(2)); } - @Test - @DisplayName("only attempts to delete undeletable directories once") - void onlyAttemptsToDeleteUndeletableDirectoriesOnce() { - var results = executeTestsForClass(UndeletableDirectoryTestCase.class); - - assertSingleFailedTest(results, // - instanceOf(IOException.class), // - message(it -> it.startsWith("Failed to delete temp directory")), // - message(it -> it.endsWith( - "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"))); + @TestFactory + @DisplayName("only attempts to delete undeletable paths once") + Stream onlyAttemptsToDeleteUndeletablePathsOnce() { + return Stream.of( // + dynamicTest("directory", () -> onlyAttemptsToDeleteUndeletablePathOnce(UndeletableDirectoryTestCase.class)), // + dynamicTest("file", () -> onlyAttemptsToDeleteUndeletablePathOnce(UndeletableFileTestCase.class)) // + ); } - @Test - @DisplayName("only attempts to delete undeletable files once") - void onlyAttemptsToDeleteUndeletableFilesOnce() { - var results = executeTestsForClass(UndeletableFileTestCase.class); + private void onlyAttemptsToDeleteUndeletablePathOnce(Class testClass) { + var results = executeTestsForClass(testClass); + + var tempDir = results.testEvents().reportingEntryPublished().stream().map( + it -> it.getPayload(ReportEntry.class).orElseThrow()).map( + it -> Path.of(it.getKeyValuePairs().get(UndeletableTestCase.TEMP_DIR))).findAny().orElseThrow(); assertSingleFailedTest(results, // instanceOf(IOException.class), // - message(it -> it.startsWith("Failed to delete temp directory")), // - message(it -> it.endsWith( - "The following paths could not be deleted (see suppressed exceptions for details): , undeletable")), // + 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"))); } @@ -1028,15 +1026,16 @@ private static Map getTempDirs(TestInfo testInfo) { } } - static class UndeletableDirectoryTestCase { + static class UndeletableTestCase { - static final Path UNDELETABLE_SUB_DIR = Path.of("undeletable"); + static final Path UNDELETABLE_PATH = Path.of("undeletable"); + static final String TEMP_DIR = "TEMP_DIR"; @RegisterExtension BeforeEachCallback injector = context -> context // .getStore(TempDirectory.NAMESPACE) // .put(TempDirectory.FILE_OPERATIONS_KEY, (FileOperations) path -> { - if (path.endsWith(UNDELETABLE_SUB_DIR)) { + if (path.endsWith(UNDELETABLE_PATH)) { throw new IOException("Simulated failure"); } else { @@ -1044,31 +1043,26 @@ static class UndeletableDirectoryTestCase { } }); - @Test - void test(@TempDir Path tempDir) throws Exception { - Files.createDirectory(tempDir.resolve(UNDELETABLE_SUB_DIR)); + @TempDir + Path tempDir; + + @BeforeEach + void reportTempDir(TestReporter reporter) { + reporter.publishEntry(TEMP_DIR, tempDir.toString()); } } - static class UndeletableFileTestCase { - - static final Path UNDELETABLE_FILE = Path.of("undeletable"); - - @RegisterExtension - BeforeEachCallback injector = context -> context // - .getStore(TempDirectory.NAMESPACE) // - .put(TempDirectory.FILE_OPERATIONS_KEY, (FileOperations) path -> { - if (path.endsWith(UNDELETABLE_FILE)) { - throw new IOException("Simulated failure"); - } - else { - Files.delete(path); - } - }); + static class UndeletableDirectoryTestCase extends UndeletableTestCase { + @Test + void test() throws Exception { + Files.createDirectory(tempDir.resolve(UNDELETABLE_PATH)); + } + } + static class UndeletableFileTestCase extends UndeletableTestCase { @Test - void test(@TempDir Path tempDir) throws Exception { - Files.createFile(tempDir.resolve(UNDELETABLE_FILE)); + void test() throws Exception { + Files.createFile(tempDir.resolve(UNDELETABLE_PATH)); } } } From 3f186194bda523b22e60ec2c5dcd87a638850918 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 22 Apr 2023 14:52:08 +0200 Subject: [PATCH 12/25] Add 5.9.3 release notes --- .../docs/asciidoc/release-notes/index.adoc | 2 + .../release-notes/release-notes-5.9.3.adoc | 58 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc diff --git a/documentation/src/docs/asciidoc/release-notes/index.adoc b/documentation/src/docs/asciidoc/release-notes/index.adoc index ceabf38312a2..6b41a3649a5e 100644 --- a/documentation/src/docs/asciidoc/release-notes/index.adoc +++ b/documentation/src/docs/asciidoc/release-notes/index.adoc @@ -16,6 +16,8 @@ authors as well as build tool and IDE vendors. include::{includedir}/link-attributes.adoc[] +include::{basedir}/release-notes-5.9.3.adoc[] + include::{basedir}/release-notes-5.9.2.adoc[] include::{basedir}/release-notes-5.9.1.adoc[] diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc new file mode 100644 index 000000000000..bc912326c369 --- /dev/null +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc @@ -0,0 +1,58 @@ +[[release-notes-5.9.3]] +== 5.9.3 + +*Date of Release:* ❓ + +*Scope:* ❓ + +For a complete list of all _closed_ issues and pull requests for this release, consult the +link:{junit5-repo}+/milestone/67?closed=1+[5.9.3] milestone page in the +JUnit repository on GitHub. + + +[[release-notes-5.9.3-junit-platform]] +=== JUnit Platform + +==== Bug Fixes + +* ❓ + +==== Deprecations and Breaking Changes + +* ❓ + +==== New Features and Improvements + +* ❓ + + +[[release-notes-5.9.3-junit-jupiter]] +=== JUnit Jupiter + +==== Bug Fixes + +* ❓ + +==== Deprecations and Breaking Changes + +* ❓ + +==== New Features and Improvements + +* ❓ + + += [[release-notes-5.9.3-junit-vintage]] +=== JUnit Vintage + +==== Bug Fixes + +* ❓ + +==== Deprecations and Breaking Changes + +* ❓ + +==== New Features and Improvements + +* ❓ From 5427a9bb68c0e949d42ec64f9a16a0f92589116b Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 22 Apr 2023 14:53:29 +0200 Subject: [PATCH 13/25] Move release notes entry for #3236 to 5.9.3 --- .../src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc index bc912326c369..de65c7777c0a 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc @@ -31,7 +31,8 @@ JUnit repository on GitHub. ==== Bug Fixes -* ❓ +* Exceptions thrown for undeletable files when cleaning up a temporary directory created + via `@TempDir` now include the root cause. ==== Deprecations and Breaking Changes From ee3405269a35ad9cc00af4bc64a3c914a06c7a1f Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 22 Apr 2023 15:01:21 +0200 Subject: [PATCH 14/25] Revert disallowing private lifecycle methods Document using private as being strongly discouraged. Resolves #3242. (cherry picked from commit 594f7e403ccf6bd758ca91008328272bf996f250) --- .../release-notes/release-notes-5.9.3.adoc | 2 + .../java/org/junit/jupiter/api/AfterAll.java | 13 ++-- .../java/org/junit/jupiter/api/AfterEach.java | 5 +- .../java/org/junit/jupiter/api/BeforeAll.java | 13 ++-- .../org/junit/jupiter/api/BeforeEach.java | 5 +- .../descriptor/LifecycleMethodUtils.java | 13 +--- ...alidLifecycleMethodConfigurationTests.java | 78 ++----------------- 7 files changed, 30 insertions(+), 99 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc index de65c7777c0a..4e0da156e26f 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc @@ -33,6 +33,8 @@ JUnit repository on GitHub. * Exceptions thrown for undeletable files when cleaning up a temporary directory created via `@TempDir` now include the root cause. +* Allow lifecycle methods to be declared as `private` again for backwards compatibility + but document it as a discouraged practice. ==== Deprecations and Breaking Changes 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 061ee118c4c5..52743ebef416 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 @@ -29,17 +29,20 @@ * *

Method Signatures

* - *

{@code @AfterAll} methods must have a {@code void} return type, must not - * be {@code private}, and must be {@code static} by default. Consequently, - * {@code @AfterAll} methods are not supported in {@link Nested @Nested} test - * classes or as interface default methods unless the test class is - * annotated with {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}. + *

{@code @AfterAll} methods must have a {@code void} return type and must be + * {@code static} by default. Consequently, {@code @AfterAll} methods are not + * supported in {@link Nested @Nested} test classes or as interface default + * methods unless the test class is annotated with + * {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}. * However, beginning with Java 16 {@code @AfterAll} methods may be declared as * {@code static} in {@link Nested @Nested} test classes, and the * {@code Lifecycle.PER_CLASS} restriction no longer applies. {@code @AfterAll} * 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 + * strongly discouraged and will be disallowed in a future release. + * *

Inheritance and Execution Order

* *

{@code @AfterAll} methods are inherited from superclasses as long as diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterEach.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterEach.java index df5a522e114f..8dfd018fa4f9 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterEach.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/AfterEach.java @@ -28,8 +28,9 @@ * *

Method Signatures

* - *

{@code @AfterEach} methods must have a {@code void} return type, - * must not be {@code private}, and must not be {@code static}. + *

{@code @AfterEach} methods must have a {@code void} return type and must + * not be {@code static}. Using {@code private} visibility is strongly + * discouraged and will be disallowed in a future release. * They may optionally declare parameters to be resolved by * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolvers}. * diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeAll.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeAll.java index 01b56d393c1a..30eba9b73746 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeAll.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeAll.java @@ -29,17 +29,20 @@ * *

Method Signatures

* - *

{@code @BeforeAll} methods must have a {@code void} return type, must not - * be {@code private}, and must be {@code static} by default. Consequently, - * {@code @BeforeAll} methods are not supported in {@link Nested @Nested} test - * classes or as interface default methods unless the test class is - * annotated with {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}. + *

{@code @BeforeAll} methods must have a {@code void} return type and must + * be {@code static} by default. Consequently, {@code @BeforeAll} methods are + * not supported in {@link Nested @Nested} test classes or as interface + * default methods unless the test class is annotated with + * {@link TestInstance @TestInstance(Lifecycle.PER_CLASS)}. * However, beginning with Java 16 {@code @BeforeAll} methods may be declared as * {@code static} in {@link Nested @Nested} test classes, and the * {@code Lifecycle.PER_CLASS} restriction no longer applies. {@code @BeforeAll} * 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 + * strongly discouraged and will be disallowed in a future release. + * *

Inheritance and Execution Order

* *

{@code @BeforeAll} methods are inherited from superclasses as long as diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeEach.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeEach.java index 79d0f73f0b4d..37ca2498c889 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeEach.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/BeforeEach.java @@ -28,8 +28,9 @@ * *

Method Signatures

* - *

{@code @BeforeEach} methods must have a {@code void} return type, - * must not be {@code private}, and must not be {@code static}. + *

{@code @BeforeEach} methods must have a {@code void} return type and must + * not be {@code static}. Using {@code private} visibility is strongly + * discouraged and will be disallowed in a future release. * They may optionally declare parameters to be resolved by * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolvers}. * diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtils.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtils.java index 27c90790b140..9adb38ff3945 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtils.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/LifecycleMethodUtils.java @@ -61,7 +61,6 @@ private static List findMethodsAndAssertStaticAndNonPrivate(Class tes if (requireStatic) { methods.forEach(method -> assertStatic(annotationType, method)); } - methods.forEach(method -> assertNonPrivate(annotationType, method)); return methods; } @@ -69,10 +68,7 @@ private static List findMethodsAndAssertNonStaticAndNonPrivate(Class Class annotationType, HierarchyTraversalMode traversalMode) { List methods = findMethodsAndCheckVoidReturnType(testClass, annotationType, traversalMode); - methods.forEach(method -> { - assertNonStatic(annotationType, method); - assertNonPrivate(annotationType, method); - }); + methods.forEach(method -> assertNonStatic(annotationType, method)); return methods; } @@ -99,13 +95,6 @@ private static void assertNonStatic(Class annotationType, } } - private static void assertNonPrivate(Class annotationType, Method method) { - if (ReflectionUtils.isPrivate(method)) { - throw new JUnitException(String.format("@%s method '%s' must not be private.", - annotationType.getSimpleName(), method.toGenericString())); - } - } - private static void assertVoid(Class annotationType, Method method) { if (!returnsVoid(method)) { throw new JUnitException(String.format("@%s method '%s' must not return a value.", diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/InvalidLifecycleMethodConfigurationTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/InvalidLifecycleMethodConfigurationTests.java index 87cffb5af787..37dc164993ab 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/InvalidLifecycleMethodConfigurationTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/InvalidLifecycleMethodConfigurationTests.java @@ -35,45 +35,25 @@ class InvalidLifecycleMethodConfigurationTests extends AbstractJupiterTestEngine @Test void executeValidTestCaseAlongsideTestCaseWithInvalidNonStaticBeforeAllDeclaration() { - assertExecutionResults(TestCaseWithInvalidNonStaticBeforeAllMethod.class); - } - - @Test - void executeValidTestCaseAlongsideTestCaseWithInvalidPrivateBeforeAllDeclaration() { - assertExecutionResults(TestCaseWithInvalidPrivateBeforeAllMethod.class); + assertContainerFailed(TestCaseWithInvalidNonStaticBeforeAllMethod.class); } @Test void executeValidTestCaseAlongsideTestCaseWithInvalidNonStaticAfterAllDeclaration() { - assertExecutionResults(TestCaseWithInvalidNonStaticAfterAllMethod.class); - } - - @Test - void executeValidTestCaseAlongsideTestCaseWithInvalidPrivateAfterAllDeclaration() { - assertExecutionResults(TestCaseWithInvalidPrivateAfterAllMethod.class); + assertContainerFailed(TestCaseWithInvalidNonStaticAfterAllMethod.class); } @Test void executeValidTestCaseAlongsideTestCaseWithInvalidStaticBeforeEachDeclaration() { - assertExecutionResults(TestCaseWithInvalidStaticBeforeEachMethod.class); - } - - @Test - void executeValidTestCaseAlongsideTestCaseWithInvalidPrivateBeforeEachDeclaration() { - assertExecutionResults(TestCaseWithInvalidPrivateBeforeEachMethod.class); + assertContainerFailed(TestCaseWithInvalidStaticBeforeEachMethod.class); } @Test void executeValidTestCaseAlongsideTestCaseWithInvalidStaticAfterEachDeclaration() { - assertExecutionResults(TestCaseWithInvalidStaticAfterEachMethod.class); - } - - @Test - void executeValidTestCaseAlongsideTestCaseWithInvalidPrivateAfterEachDeclaration() { - assertExecutionResults(TestCaseWithInvalidPrivateAfterEachMethod.class); + assertContainerFailed(TestCaseWithInvalidStaticAfterEachMethod.class); } - private void assertExecutionResults(Class invalidTestClass) { + private void assertContainerFailed(Class invalidTestClass) { EngineExecutionResults executionResults = executeTests(selectClass(TestCase.class), selectClass(invalidTestClass)); Events containers = executionResults.containerEvents(); @@ -112,18 +92,6 @@ void test() { } } - static class TestCaseWithInvalidPrivateBeforeAllMethod { - - // must not be private - @BeforeAll - private static void beforeAll() { - } - - @Test - void test() { - } - } - static class TestCaseWithInvalidNonStaticAfterAllMethod { // must be static @@ -136,18 +104,6 @@ void test() { } } - static class TestCaseWithInvalidPrivateAfterAllMethod { - - // must not be private - @AfterAll - private static void afterAll() { - } - - @Test - void test() { - } - } - static class TestCaseWithInvalidStaticBeforeEachMethod { // must NOT be static @@ -160,18 +116,6 @@ void test() { } } - static class TestCaseWithInvalidPrivateBeforeEachMethod { - - // must NOT be private - @BeforeEach - private void beforeEach() { - } - - @Test - void test() { - } - } - static class TestCaseWithInvalidStaticAfterEachMethod { // must NOT be static @@ -184,16 +128,4 @@ void test() { } } - static class TestCaseWithInvalidPrivateAfterEachMethod { - - // must NOT be private - @AfterEach - private void afterEach() { - } - - @Test - void test() { - } - } - } From e99921b955902b727bc8afcc60ff406bde6fb86f Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 20 Jan 2023 13:35:27 +0100 Subject: [PATCH 15/25] Migrate to Mockito.mock(T...) where feasible --- .../AbstractExecutionConditionTests.java | 2 +- .../support/TypeBasedParameterResolverTests.java | 6 +++--- .../config/CachingJupiterConfigurationTests.java | 2 +- .../config/DefaultJupiterConfigurationTests.java | 12 ++++++------ ...atingConfigurationParameterConverterTests.java | 14 +++++++------- .../engine/descriptor/DisplayNameUtilsTests.java | 6 +++--- .../engine/descriptor/ExtensionContextTests.java | 2 +- .../descriptor/JupiterTestDescriptorTests.java | 2 +- .../TestFactoryTestDescriptorTests.java | 12 +++++------- .../TestInstanceLifecycleUtilsTests.java | 15 ++++++--------- ...TestTemplateInvocationTestDescriptorTests.java | 4 ++-- .../TestTemplateTestDescriptorTests.java | 2 +- .../discovery/DiscoverySelectorResolverTests.java | 4 ++-- .../execution/AbstractExecutableInvokerTests.java | 6 +++--- .../JupiterEngineExecutionContextTests.java | 14 +++++++------- .../execution/ParameterResolutionUtilsTests.java | 6 +++--- .../extension/CloseablePathCleanupTests.java | 2 +- .../engine/extension/ExtensionRegistryTests.java | 2 +- .../TestReporterParameterResolverTests.java | 8 +++----- .../extension/TimeoutConfigurationTests.java | 2 +- .../ParameterizedTestNameFormatterTests.java | 6 ++---- .../converter/TypedArgumentConverterTests.java | 4 ++-- .../provider/EnumArgumentsProviderTests.java | 3 +-- .../provider/MethodArgumentsProviderTests.java | 2 +- .../ConsoleLauncherExecutionResultTests.java | 2 +- .../platform/console/tasks/ColorPaletteTests.java | 3 +-- ...rallelExecutionConfigurationStrategyTests.java | 2 +- .../junit/platform/launcher/TestPlanTests.java | 2 +- .../core/CompositeTestExecutionListenerTests.java | 7 ++----- .../core/ExecutionListenerAdapterTests.java | 5 +---- .../listeners/SummaryGenerationTests.java | 3 +-- .../legacy/LegacyReportingUtilsTests.java | 5 ++--- .../LegacyXmlReportGeneratingListenerTests.java | 7 +++---- .../reporting/legacy/xml/XmlReportDataTests.java | 2 +- .../legacy/xml/XmlReportWriterTests.java | 2 +- .../platform/runner/JUnitPlatformRunnerTests.java | 7 +++---- 36 files changed, 82 insertions(+), 103 deletions(-) diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/condition/AbstractExecutionConditionTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/condition/AbstractExecutionConditionTests.java index 7a21eb3b7e6c..7e02a7d3360b 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/condition/AbstractExecutionConditionTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/condition/AbstractExecutionConditionTests.java @@ -50,7 +50,7 @@ @TestInstance(Lifecycle.PER_CLASS) abstract class AbstractExecutionConditionTests { - private final ExtensionContext context = mock(ExtensionContext.class); + private final ExtensionContext context = mock(); private ConditionEvaluationResult result; diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolverTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolverTests.java index 3c02d637d0f7..40a333efb5d8 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolverTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/api/extension/support/TypeBasedParameterResolverTests.java @@ -14,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.lang.annotation.ElementType; @@ -32,7 +33,6 @@ import org.junit.jupiter.api.extension.ParameterResolver; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.ReflectionUtils; -import org.mockito.Mockito; /** * @since 5.6 @@ -86,13 +86,13 @@ void resolve() { } private static ParameterContext parameterContext(Parameter parameter) { - ParameterContext parameterContext = Mockito.mock(ParameterContext.class); + ParameterContext parameterContext = mock(); when(parameterContext.getParameter()).thenReturn(parameter); return parameterContext; } private static ExtensionContext extensionContext() { - ExtensionContext extensionContext = Mockito.mock(ExtensionContext.class); + ExtensionContext extensionContext = mock(); when(extensionContext.getDisplayName()).thenReturn("Displaying"); return extensionContext; } diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/CachingJupiterConfigurationTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/CachingJupiterConfigurationTests.java index 8c7fc8681bf5..cb4f88f73b47 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/CachingJupiterConfigurationTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/CachingJupiterConfigurationTests.java @@ -34,7 +34,7 @@ */ class CachingJupiterConfigurationTests { - private final JupiterConfiguration delegate = mock(JupiterConfiguration.class); + private final JupiterConfiguration delegate = mock(); private final JupiterConfiguration cache = new CachingJupiterConfiguration(delegate); @Test diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java index 1f527013eb08..2592fe256b35 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/DefaultJupiterConfigurationTests.java @@ -45,14 +45,14 @@ void getDefaultTestInstanceLifecyclePreconditions() { @Test void getDefaultTestInstanceLifecycleWithNoConfigParamSet() { - JupiterConfiguration configuration = new DefaultJupiterConfiguration(mock(ConfigurationParameters.class)); + JupiterConfiguration configuration = new DefaultJupiterConfiguration(mock()); Lifecycle lifecycle = configuration.getDefaultTestInstanceLifecycle(); assertThat(lifecycle).isEqualTo(PER_METHOD); } @Test void getDefaultTempDirCleanupModeWithNoConfigParamSet() { - JupiterConfiguration configuration = new DefaultJupiterConfiguration(mock(ConfigurationParameters.class)); + JupiterConfiguration configuration = new DefaultJupiterConfiguration(mock()); CleanupMode cleanupMode = configuration.getDefaultTempDirCleanupMode(); assertThat(cleanupMode).isEqualTo(ALWAYS); } @@ -74,7 +74,7 @@ void getDefaultTestInstanceLifecycleWithConfigParamSet() { @Test void shouldGetDefaultDisplayNameGeneratorWithConfigParamSet() { - ConfigurationParameters parameters = mock(ConfigurationParameters.class); + ConfigurationParameters parameters = mock(); String key = Constants.DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME; when(parameters.get(key)).thenReturn(Optional.of(CustomDisplayNameGenerator.class.getName())); JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters); @@ -86,7 +86,7 @@ void shouldGetDefaultDisplayNameGeneratorWithConfigParamSet() { @Test void shouldGetStandardAsDefaultDisplayNameGeneratorWithoutConfigParamSet() { - ConfigurationParameters parameters = mock(ConfigurationParameters.class); + ConfigurationParameters parameters = mock(); String key = Constants.DEFAULT_DISPLAY_NAME_GENERATOR_PROPERTY_NAME; when(parameters.get(key)).thenReturn(Optional.empty()); JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters); @@ -98,7 +98,7 @@ void shouldGetStandardAsDefaultDisplayNameGeneratorWithoutConfigParamSet() { @Test void shouldGetNothingAsDefaultTestMethodOrderWithoutConfigParamSet() { - ConfigurationParameters parameters = mock(ConfigurationParameters.class); + ConfigurationParameters parameters = mock(); String key = Constants.DEFAULT_TEST_METHOD_ORDER_PROPERTY_NAME; when(parameters.get(key)).thenReturn(Optional.empty()); JupiterConfiguration configuration = new DefaultJupiterConfiguration(parameters); @@ -109,7 +109,7 @@ void shouldGetNothingAsDefaultTestMethodOrderWithoutConfigParamSet() { } private void assertDefaultConfigParam(String configValue, Lifecycle expected) { - ConfigurationParameters configParams = mock(ConfigurationParameters.class); + ConfigurationParameters configParams = mock(); when(configParams.get(KEY)).thenReturn(Optional.ofNullable(configValue)); Lifecycle lifecycle = new DefaultJupiterConfiguration(configParams).getDefaultTestInstanceLifecycle(); assertThat(lifecycle).isEqualTo(expected); diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverterTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverterTests.java index 6923183aedce..5848cda93b4a 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverterTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/config/InstantiatingConfigurationParameterConverterTests.java @@ -38,7 +38,7 @@ class InstantiatingConfigurationParameterConverterTests { @Test void shouldInstantiateConfiguredClass(LogRecordListener listener) { - ConfigurationParameters configurationParameters = mock(ConfigurationParameters.class); + ConfigurationParameters configurationParameters = mock(); when(configurationParameters.get(KEY)).thenReturn(Optional.of(CustomDisplayNameGenerator.class.getName())); InstantiatingConfigurationParameterConverter converter = new InstantiatingConfigurationParameterConverter<>( @@ -54,7 +54,7 @@ void shouldInstantiateConfiguredClass(LogRecordListener listener) { @Test void shouldReturnEmptyOptionalIfNoConfigurationFound() { - ConfigurationParameters configurationParameters = mock(ConfigurationParameters.class); + ConfigurationParameters configurationParameters = mock(); when(configurationParameters.get(KEY)).thenReturn(Optional.empty()); InstantiatingConfigurationParameterConverter converter = new InstantiatingConfigurationParameterConverter<>( @@ -66,7 +66,7 @@ void shouldReturnEmptyOptionalIfNoConfigurationFound() { @Test void shouldReturnEmptyOptionalIfConfigurationIsBlank() { - ConfigurationParameters configurationParameters = mock(ConfigurationParameters.class); + ConfigurationParameters configurationParameters = mock(); when(configurationParameters.get(KEY)).thenReturn(Optional.of("")); InstantiatingConfigurationParameterConverter converter = new InstantiatingConfigurationParameterConverter<>( @@ -78,7 +78,7 @@ void shouldReturnEmptyOptionalIfConfigurationIsBlank() { @Test void shouldTrimAndInstantiateConfiguredClass(LogRecordListener listener) { - ConfigurationParameters configurationParameters = mock(ConfigurationParameters.class); + ConfigurationParameters configurationParameters = mock(); String classNameWithSpaces = " " + CustomDisplayNameGenerator.class.getName() + " "; when(configurationParameters.get(KEY)).thenReturn(Optional.of(classNameWithSpaces)); @@ -95,7 +95,7 @@ void shouldTrimAndInstantiateConfiguredClass(LogRecordListener listener) { @Test void shouldReturnEmptyOptionalIfNoClassFound(LogRecordListener listener) { - ConfigurationParameters configurationParameters = mock(ConfigurationParameters.class); + ConfigurationParameters configurationParameters = mock(); when(configurationParameters.get(KEY)).thenReturn(Optional.of("random-string")); InstantiatingConfigurationParameterConverter converter = new InstantiatingConfigurationParameterConverter<>( @@ -111,7 +111,7 @@ void shouldReturnEmptyOptionalIfNoClassFound(LogRecordListener listener) { @Test void shouldReturnEmptyOptionalIfClassFoundIsNotATypeOfExpectedType(LogRecordListener listener) { - ConfigurationParameters configurationParameters = mock(ConfigurationParameters.class); + ConfigurationParameters configurationParameters = mock(); when(configurationParameters.get(KEY)).thenReturn(Optional.of(Object.class.getName())); InstantiatingConfigurationParameterConverter converter = new InstantiatingConfigurationParameterConverter<>( @@ -127,7 +127,7 @@ void shouldReturnEmptyOptionalIfClassFoundIsNotATypeOfExpectedType(LogRecordList @Test void shouldReturnEmptyOptionalIfClassNameIsNotFullyQualified(LogRecordListener listener) { - ConfigurationParameters configurationParameters = mock(ConfigurationParameters.class); + ConfigurationParameters configurationParameters = mock(); when(configurationParameters.get(KEY)).thenReturn( Optional.of(CustomDisplayNameGenerator.class.getSimpleName())); 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 7d61cf86cab6..022f93af9caf 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 @@ -71,7 +71,7 @@ void shouldGetDisplayNameFromSupplierIfNoDisplayNameAnnotationPresent() { @Nested class ClassDisplayNameSupplierTests { - private JupiterConfiguration configuration = mock(JupiterConfiguration.class); + private JupiterConfiguration configuration = mock(); @Test void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() { @@ -107,7 +107,7 @@ void shouldGetDisplayNameFromDefaultDisplayNameGenerator() { @Nested class NestedClassDisplayNameTests { - private JupiterConfiguration configuration = mock(JupiterConfiguration.class); + private JupiterConfiguration configuration = mock(); @Test void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() { @@ -131,7 +131,7 @@ void shouldGetDisplayNameFromDefaultDisplayNameGenerator() { @Nested class MethodDisplayNameTests { - private JupiterConfiguration configuration = mock(JupiterConfiguration.class); + private JupiterConfiguration configuration = mock(); @Test void shouldGetDisplayNameFromDisplayNameGenerationAnnotation() throws Exception { diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java index e9075148b54d..af140f29f877 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/ExtensionContextTests.java @@ -59,7 +59,7 @@ */ public class ExtensionContextTests { - private final JupiterConfiguration configuration = mock(JupiterConfiguration.class); + private final JupiterConfiguration configuration = mock(); @BeforeEach void setUp() { diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptorTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptorTests.java index 05a3bd435214..ecd65438b861 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptorTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptorTests.java @@ -53,7 +53,7 @@ class JupiterTestDescriptorTests { private static final UniqueId uniqueId = UniqueId.root("enigma", "foo"); - private final JupiterConfiguration configuration = mock(JupiterConfiguration.class); + private final JupiterConfiguration configuration = mock(); @BeforeEach void setUp() { diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java index 530454f56bc5..7718e771ae2f 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestFactoryTestDescriptorTests.java @@ -30,7 +30,6 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext; -import org.junit.jupiter.engine.extension.MutableExtensionRegistry; import org.junit.platform.engine.TestSource; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.support.descriptor.ClasspathResourceSource; @@ -39,7 +38,6 @@ import org.junit.platform.engine.support.descriptor.FileSource; import org.junit.platform.engine.support.descriptor.MethodSource; import org.junit.platform.engine.support.descriptor.UriSource; -import org.junit.platform.engine.support.hierarchical.Node; import org.junit.platform.engine.support.hierarchical.OpenTest4JAwareThrowableCollector; /** @@ -134,17 +132,17 @@ class Streams { @BeforeEach void before() throws Exception { - jupiterConfiguration = mock(JupiterConfiguration.class); + jupiterConfiguration = mock(); when(jupiterConfiguration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); - extensionContext = mock(ExtensionContext.class); + extensionContext = mock(); isClosed = false; context = new JupiterEngineExecutionContext(null, null) // .extend() // .withThrowableCollector(new OpenTest4JAwareThrowableCollector()) // .withExtensionContext(extensionContext) // - .withExtensionRegistry(mock(MutableExtensionRegistry.class)) // + .withExtensionRegistry(mock()) // .build(); Method testMethod = CustomStreamTestCase.class.getDeclaredMethod("customStream"); @@ -158,7 +156,7 @@ void streamsFromTestFactoriesShouldBeClosed() { Stream dynamicTestStream = Stream.empty(); prepareMockForTestInstanceWithCustomStream(dynamicTestStream); - descriptor.invokeTestMethod(context, mock(Node.DynamicTestExecutor.class)); + descriptor.invokeTestMethod(context, mock()); assertTrue(isClosed); } @@ -168,7 +166,7 @@ void streamsFromTestFactoriesShouldBeClosedWhenTheyThrow() { Stream integerStream = Stream.of(1, 2); prepareMockForTestInstanceWithCustomStream(integerStream); - descriptor.invokeTestMethod(context, mock(Node.DynamicTestExecutor.class)); + descriptor.invokeTestMethod(context, mock()); assertTrue(isClosed); } diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtilsTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtilsTests.java index 080e42840be8..46fab2deece5 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtilsTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestInstanceLifecycleUtilsTests.java @@ -50,7 +50,7 @@ class TestInstanceLifecycleUtilsTests { @Test void getTestInstanceLifecyclePreconditions() { PreconditionViolationException exception = assertThrows(PreconditionViolationException.class, - () -> getTestInstanceLifecycle(null, new DefaultJupiterConfiguration(mock(ConfigurationParameters.class)))); + () -> getTestInstanceLifecycle(null, new DefaultJupiterConfiguration(mock()))); assertThat(exception).hasMessage("testClass must not be null"); exception = assertThrows(PreconditionViolationException.class, @@ -60,14 +60,13 @@ void getTestInstanceLifecyclePreconditions() { @Test void getTestInstanceLifecycleWithNoConfigParamSet() { - Lifecycle lifecycle = getTestInstanceLifecycle(getClass(), - new DefaultJupiterConfiguration(mock(ConfigurationParameters.class))); + Lifecycle lifecycle = getTestInstanceLifecycle(getClass(), new DefaultJupiterConfiguration(mock())); assertThat(lifecycle).isEqualTo(PER_METHOD); } @Test void getTestInstanceLifecycleWithConfigParamSet() { - ConfigurationParameters configParams = mock(ConfigurationParameters.class); + ConfigurationParameters configParams = mock(); when(configParams.get(KEY)).thenReturn(Optional.of(PER_CLASS.name().toLowerCase())); Lifecycle lifecycle = getTestInstanceLifecycle(getClass(), new DefaultJupiterConfiguration(configParams)); assertThat(lifecycle).isEqualTo(PER_CLASS); @@ -75,7 +74,7 @@ void getTestInstanceLifecycleWithConfigParamSet() { @Test void getTestInstanceLifecycleWithLocalConfigThatOverridesCustomDefaultSetViaConfigParam() { - ConfigurationParameters configParams = mock(ConfigurationParameters.class); + ConfigurationParameters configParams = mock(); when(configParams.get(KEY)).thenReturn(Optional.of(PER_CLASS.name().toLowerCase())); Lifecycle lifecycle = getTestInstanceLifecycle(TestCase.class, new DefaultJupiterConfiguration(configParams)); assertThat(lifecycle).isEqualTo(PER_METHOD); @@ -84,16 +83,14 @@ void getTestInstanceLifecycleWithLocalConfigThatOverridesCustomDefaultSetViaConf @Test void getTestInstanceLifecycleFromMetaAnnotationWithNoConfigParamSet() { Class testClass = BaseMetaAnnotatedTestCase.class; - Lifecycle lifecycle = getTestInstanceLifecycle(testClass, - new DefaultJupiterConfiguration(mock(ConfigurationParameters.class))); + Lifecycle lifecycle = getTestInstanceLifecycle(testClass, new DefaultJupiterConfiguration(mock())); assertThat(lifecycle).isEqualTo(PER_CLASS); } @Test void getTestInstanceLifecycleFromSpecializedClassWithNoConfigParamSet() { Class testClass = SpecializedTestCase.class; - Lifecycle lifecycle = getTestInstanceLifecycle(testClass, - new DefaultJupiterConfiguration(mock(ConfigurationParameters.class))); + Lifecycle lifecycle = getTestInstanceLifecycle(testClass, new DefaultJupiterConfiguration(mock())); assertThat(lifecycle).isEqualTo(PER_CLASS); } diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java index 78d92bfcb2c3..b00060eb8e0b 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateInvocationTestDescriptorTests.java @@ -31,11 +31,11 @@ class TestTemplateInvocationTestDescriptorTests { void invocationsDoNotDeclareExclusiveResources() throws Exception { Class testClass = MyTestCase.class; Method testTemplateMethod = testClass.getDeclaredMethod("testTemplate"); - JupiterConfiguration configuration = mock(JupiterConfiguration.class); + JupiterConfiguration configuration = mock(); when(configuration.getDefaultDisplayNameGenerator()).thenReturn(new DisplayNameGenerator.Standard()); TestTemplateTestDescriptor parent = new TestTemplateTestDescriptor(UniqueId.root("segment", "template"), testClass, testTemplateMethod, configuration); - TestTemplateInvocationContext invocationContext = mock(TestTemplateInvocationContext.class); + TestTemplateInvocationContext invocationContext = mock(); when(invocationContext.getDisplayName(anyInt())).thenReturn("invocation"); TestTemplateInvocationTestDescriptor testDescriptor = new TestTemplateInvocationTestDescriptor( diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java index b808248cb804..f9649ddac33f 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/descriptor/TestTemplateTestDescriptorTests.java @@ -32,7 +32,7 @@ * @since 5.0 */ class TestTemplateTestDescriptorTests { - private JupiterConfiguration jupiterConfiguration = mock(JupiterConfiguration.class); + private JupiterConfiguration jupiterConfiguration = mock(); @Test void inheritsTagsFromParent() throws Exception { diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolverTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolverTests.java index 0798a2ca9e67..a71d0665e14b 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolverTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/discovery/DiscoverySelectorResolverTests.java @@ -91,8 +91,8 @@ */ class DiscoverySelectorResolverTests { - private final JupiterConfiguration configuration = mock(JupiterConfiguration.class); - private final LauncherDiscoveryListener discoveryListener = mock(LauncherDiscoveryListener.class); + private final JupiterConfiguration configuration = mock(); + private final LauncherDiscoveryListener discoveryListener = mock(); private final JupiterEngineDescriptor engineDescriptor = new JupiterEngineDescriptor(engineId(), configuration); @BeforeEach diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/AbstractExecutableInvokerTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/AbstractExecutableInvokerTests.java index f633790b34ac..786782339281 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/AbstractExecutableInvokerTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/AbstractExecutableInvokerTests.java @@ -37,12 +37,12 @@ abstract class AbstractExecutableInvokerTests { private static final String ENIGMA = "enigma"; - protected final MethodSource instance = mock(MethodSource.class); + protected final MethodSource instance = mock(); protected Method method; - protected final ExtensionContext extensionContext = mock(ExtensionContext.class); + protected final ExtensionContext extensionContext = mock(); - private final JupiterConfiguration configuration = mock(JupiterConfiguration.class); + private final JupiterConfiguration configuration = mock(); protected final MutableExtensionRegistry extensionRegistry = MutableExtensionRegistry.createRegistryWithDefaultExtensions( configuration); 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 50696360fcfb..d6e619d886bd 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 @@ -35,9 +35,9 @@ */ class JupiterEngineExecutionContextTests { - private final JupiterConfiguration configuration = mock(JupiterConfiguration.class); + private final JupiterConfiguration configuration = mock(); - private final EngineExecutionListener engineExecutionListener = mock(EngineExecutionListener.class); + private final EngineExecutionListener engineExecutionListener = mock(); private final JupiterEngineExecutionContext originalContext = new JupiterEngineExecutionContext( engineExecutionListener, configuration); @@ -51,10 +51,10 @@ void executionListenerIsHandedOnWhenContextIsExtended() { @Test void extendWithAllAttributes() { - ExtensionContext extensionContext = mock(ExtensionContext.class); + ExtensionContext extensionContext = mock(); MutableExtensionRegistry extensionRegistry = MutableExtensionRegistry.createRegistryWithDefaultExtensions( configuration); - TestInstancesProvider testInstancesProvider = mock(TestInstancesProvider.class); + TestInstancesProvider testInstancesProvider = mock(); JupiterEngineExecutionContext newContext = originalContext.extend() // .withExtensionContext(extensionContext) // .withExtensionRegistry(extensionRegistry) // @@ -68,11 +68,11 @@ void extendWithAllAttributes() { @Test void canOverrideAttributeWhenContextIsExtended() { - ExtensionContext extensionContext = mock(ExtensionContext.class); + ExtensionContext extensionContext = mock(); MutableExtensionRegistry extensionRegistry = MutableExtensionRegistry.createRegistryWithDefaultExtensions( configuration); - TestInstancesProvider testInstancesProvider = mock(TestInstancesProvider.class); - ExtensionContext newExtensionContext = mock(ExtensionContext.class); + TestInstancesProvider testInstancesProvider = mock(); + ExtensionContext newExtensionContext = mock(); JupiterEngineExecutionContext newContext = originalContext.extend() // .withExtensionContext(extensionContext) // diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/ParameterResolutionUtilsTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/ParameterResolutionUtilsTests.java index 8bdcbb2adeb3..1c371f6f775f 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/ParameterResolutionUtilsTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/execution/ParameterResolutionUtilsTests.java @@ -43,12 +43,12 @@ class ParameterResolutionUtilsTests { private static final String ENIGMA = "enigma"; - private final MethodSource instance = mock(MethodSource.class); + private final MethodSource instance = mock(); private Method method; - private final ExtensionContext extensionContext = mock(ExtensionContext.class); + private final ExtensionContext extensionContext = mock(); - private final JupiterConfiguration configuration = mock(JupiterConfiguration.class); + private final JupiterConfiguration configuration = mock(); private final MutableExtensionRegistry extensionRegistry = MutableExtensionRegistry.createRegistryWithDefaultExtensions( configuration); diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/CloseablePathCleanupTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/CloseablePathCleanupTests.java index a2d6b710dfe7..7d9557609345 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/CloseablePathCleanupTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/CloseablePathCleanupTests.java @@ -44,7 +44,7 @@ */ class CloseablePathCleanupTests extends AbstractJupiterTestEngineTests { - private final ExtensionContext extensionContext = mock(ExtensionContext.class); + private final ExtensionContext extensionContext = mock(); private TempDirectory.CloseablePath closeablePath; diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistryTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistryTests.java index b7000fbc63da..cbe91c6ea9f6 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistryTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/ExtensionRegistryTests.java @@ -41,7 +41,7 @@ class ExtensionRegistryTests { private static final int NUM_DEFAULT_EXTENSIONS = 6; - private final JupiterConfiguration configuration = mock(JupiterConfiguration.class); + private final JupiterConfiguration configuration = mock(); private MutableExtensionRegistry registry = createRegistryWithDefaultExtensions(configuration); diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TestReporterParameterResolverTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TestReporterParameterResolverTests.java index 2dbc6e8e723e..6acbcafa6126 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TestReporterParameterResolverTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TestReporterParameterResolverTests.java @@ -13,6 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.lang.reflect.Method; @@ -20,10 +21,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestReporter; -import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.platform.commons.util.ReflectionUtils; -import org.mockito.Mockito; /** * @since 5.0 @@ -45,8 +44,7 @@ void supports() { void resolve() { Parameter parameter = findParameterOfMethod("methodWithTestReporterParameter", TestReporter.class); - TestReporter testReporter = this.resolver.resolveParameter(parameterContext(parameter), - Mockito.mock(ExtensionContext.class)); + TestReporter testReporter = this.resolver.resolveParameter(parameterContext(parameter), mock()); assertNotNull(testReporter); } @@ -56,7 +54,7 @@ private Parameter findParameterOfMethod(String methodName, Class... parameter } private static ParameterContext parameterContext(Parameter parameter) { - ParameterContext parameterContext = Mockito.mock(ParameterContext.class); + ParameterContext parameterContext = mock(); when(parameterContext.getParameter()).thenReturn(parameter); return parameterContext; } 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 94b9e756eb00..d37d922fb9ad 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 @@ -47,7 +47,7 @@ */ class TimeoutConfigurationTests { - ExtensionContext extensionContext = mock(ExtensionContext.class); + ExtensionContext extensionContext = mock(); TimeoutConfiguration config = new TimeoutConfiguration(extensionContext); @Test diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java index c7a7616bd6c6..e83f88fc0f62 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java @@ -229,13 +229,11 @@ void truncatesArgumentsThatExceedMaxLength() { } private static ParameterizedTestNameFormatter formatter(String pattern, String displayName) { - return new ParameterizedTestNameFormatter(pattern, displayName, mock(ParameterizedTestMethodContext.class), - 512); + return new ParameterizedTestNameFormatter(pattern, displayName, mock(), 512); } private static ParameterizedTestNameFormatter formatter(String pattern, int argumentMaxLength) { - return new ParameterizedTestNameFormatter(pattern, "display name", mock(ParameterizedTestMethodContext.class), - argumentMaxLength); + return new ParameterizedTestNameFormatter(pattern, "display name", mock(), argumentMaxLength); } private static ParameterizedTestNameFormatter formatter(String pattern, String displayName, Method method) { diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/TypedArgumentConverterTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/TypedArgumentConverterTests.java index 2a59392cb56f..c32a0313968e 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/TypedArgumentConverterTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/converter/TypedArgumentConverterTests.java @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.lang.annotation.ElementType; @@ -30,7 +31,6 @@ import org.junit.jupiter.params.provider.ValueSource; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.ReflectionUtils; -import org.mockito.Mockito; /** * Tests for {@link TypedArgumentConverter}. @@ -92,7 +92,7 @@ void targetTypeMismatch() { } private ParameterContext parameterContext(Parameter parameter) { - ParameterContext parameterContext = Mockito.mock(ParameterContext.class); + ParameterContext parameterContext = mock(); when(parameterContext.getParameter()).thenReturn(parameter); return parameterContext; } diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java index 87a8dfd15c69..eb265d3e8ffc 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java @@ -24,14 +24,13 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.provider.EnumSource.Mode; import org.junit.platform.commons.PreconditionViolationException; -import org.mockito.Mockito; /** * @since 5.0 */ class EnumArgumentsProviderTests { - private ExtensionContext extensionContext = Mockito.mock(ExtensionContext.class); + private ExtensionContext extensionContext = mock(); @Test void providesAllEnumConstants() { diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java index c8fd3444e5c4..9d05eb9ac07d 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java @@ -366,7 +366,7 @@ class ParameterResolution { @BeforeEach void registerParameterResolver() { - JupiterConfiguration configuration = mock(JupiterConfiguration.class); + JupiterConfiguration configuration = mock(); extensionRegistry = createRegistryWithDefaultExtensions(configuration); extensionRegistry.registerExtension(StringResolver.class); } diff --git a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherExecutionResultTests.java b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherExecutionResultTests.java index fd9be9511ab9..1d37cfc93e5b 100644 --- a/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherExecutionResultTests.java +++ b/platform-tests/src/test/java/org/junit/platform/console/ConsoleLauncherExecutionResultTests.java @@ -24,7 +24,7 @@ class ConsoleLauncherExecutionResultTests { private final CommandLineOptions options = new CommandLineOptions(); - private final TestExecutionSummary summary = mock(TestExecutionSummary.class); + private final TestExecutionSummary summary = mock(); @Test void hasStatusCode0ForNoTotalFailures() { diff --git a/platform-tests/src/test/java/org/junit/platform/console/tasks/ColorPaletteTests.java b/platform-tests/src/test/java/org/junit/platform/console/tasks/ColorPaletteTests.java index a5dd82529432..3a0909c35edb 100644 --- a/platform-tests/src/test/java/org/junit/platform/console/tasks/ColorPaletteTests.java +++ b/platform-tests/src/test/java/org/junit/platform/console/tasks/ColorPaletteTests.java @@ -22,7 +22,6 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.platform.console.options.Theme; -import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.UniqueId; @@ -187,7 +186,7 @@ void flat_single_color() { private void demoTestRun(TestExecutionListener listener) { TestDescriptor testDescriptor = new TestDescriptorStub(UniqueId.forEngine("demo-engine"), "My Test"); - TestPlan testPlan = TestPlan.from(List.of(testDescriptor), mock(ConfigurationParameters.class)); + TestPlan testPlan = TestPlan.from(List.of(testDescriptor), mock()); listener.testPlanExecutionStarted(testPlan); listener.executionStarted(TestIdentifier.from(testDescriptor)); listener.executionFinished(TestIdentifier.from(testDescriptor), TestExecutionResult.successful()); diff --git a/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategyTests.java b/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategyTests.java index 5fcf9b4cb82d..b6cb64223aa9 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategyTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/support/hierarchical/DefaultParallelExecutionConfigurationStrategyTests.java @@ -30,7 +30,7 @@ */ class DefaultParallelExecutionConfigurationStrategyTests { - private ConfigurationParameters configParams = mock(ConfigurationParameters.class); + private ConfigurationParameters configParams = mock(); @BeforeEach void setUp() { diff --git a/platform-tests/src/test/java/org/junit/platform/launcher/TestPlanTests.java b/platform-tests/src/test/java/org/junit/platform/launcher/TestPlanTests.java index b5a0145511de..866e085aa438 100644 --- a/platform-tests/src/test/java/org/junit/platform/launcher/TestPlanTests.java +++ b/platform-tests/src/test/java/org/junit/platform/launcher/TestPlanTests.java @@ -23,7 +23,7 @@ class TestPlanTests { - private final ConfigurationParameters configParams = mock(ConfigurationParameters.class); + private final ConfigurationParameters configParams = mock(); private EngineDescriptor engineDescriptor = new EngineDescriptor(UniqueId.forEngine("foo"), "Foo"); diff --git a/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeTestExecutionListenerTests.java b/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeTestExecutionListenerTests.java index 9cfc55503a6b..187513476a77 100644 --- a/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeTestExecutionListenerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/launcher/core/CompositeTestExecutionListenerTests.java @@ -24,7 +24,6 @@ import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.platform.commons.logging.LogRecordListener; import org.junit.platform.commons.util.ReflectionUtils; -import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.reporting.ReportEntry; @@ -92,8 +91,7 @@ void shouldNotThrowExceptionButLogIfTesPlanExecutionStartedListenerMethodFails( LogRecordListener logRecordListener) { var testDescriptor = getDemoMethodTestDescriptor(); - compositeTestExecutionListener().testPlanExecutionStarted( - TestPlan.from(Set.of(testDescriptor), mock(ConfigurationParameters.class))); + compositeTestExecutionListener().testPlanExecutionStarted(TestPlan.from(Set.of(testDescriptor), mock())); assertThatTestListenerErrorLogged(logRecordListener, ThrowingTestExecutionListener.class, "testPlanExecutionStarted"); @@ -104,8 +102,7 @@ void shouldNotThrowExceptionButLogIfTesPlanExecutionFinishedListenerMethodFails( LogRecordListener logRecordListener) { var testDescriptor = getDemoMethodTestDescriptor(); - compositeTestExecutionListener().testPlanExecutionFinished( - TestPlan.from(Set.of(testDescriptor), mock(ConfigurationParameters.class))); + compositeTestExecutionListener().testPlanExecutionFinished(TestPlan.from(Set.of(testDescriptor), mock())); assertThatTestListenerErrorLogged(logRecordListener, ThrowingTestExecutionListener.class, "testPlanExecutionFinished"); diff --git a/platform-tests/src/test/java/org/junit/platform/launcher/core/ExecutionListenerAdapterTests.java b/platform-tests/src/test/java/org/junit/platform/launcher/core/ExecutionListenerAdapterTests.java index 7fb8ea2ef334..c120c5c79349 100644 --- a/platform-tests/src/test/java/org/junit/platform/launcher/core/ExecutionListenerAdapterTests.java +++ b/platform-tests/src/test/java/org/junit/platform/launcher/core/ExecutionListenerAdapterTests.java @@ -17,9 +17,7 @@ import org.junit.jupiter.api.Test; import org.junit.platform.commons.util.ReflectionUtils; -import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.TestDescriptor; -import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.engine.support.descriptor.DemoMethodTestDescriptor; @@ -36,8 +34,7 @@ class ExecutionListenerAdapterTests { void testReportingEntryPublished() { var testDescriptor = getSampleMethodTestDescriptor(); - var discoveryResult = new LauncherDiscoveryResult(Map.of(mock(TestEngine.class), testDescriptor), - mock(ConfigurationParameters.class)); + var discoveryResult = new LauncherDiscoveryResult(Map.of(mock(), testDescriptor), mock()); var testPlan = InternalTestPlan.from(discoveryResult); var testIdentifier = testPlan.getTestIdentifier(testDescriptor.getUniqueId()); diff --git a/platform-tests/src/test/java/org/junit/platform/launcher/listeners/SummaryGenerationTests.java b/platform-tests/src/test/java/org/junit/platform/launcher/listeners/SummaryGenerationTests.java index 76df87ffb241..7c947bf1d8d7 100644 --- a/platform-tests/src/test/java/org/junit/platform/launcher/listeners/SummaryGenerationTests.java +++ b/platform-tests/src/test/java/org/junit/platform/launcher/listeners/SummaryGenerationTests.java @@ -25,7 +25,6 @@ import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; -import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.TestSource; import org.junit.platform.engine.UniqueId; @@ -40,7 +39,7 @@ class SummaryGenerationTests { private final SummaryGeneratingListener listener = new SummaryGeneratingListener(); - private final TestPlan testPlan = TestPlan.from(List.of(), mock(ConfigurationParameters.class)); + private final TestPlan testPlan = TestPlan.from(List.of(), mock()); @Test void emptyReport() { diff --git a/platform-tests/src/test/java/org/junit/platform/reporting/legacy/LegacyReportingUtilsTests.java b/platform-tests/src/test/java/org/junit/platform/reporting/legacy/LegacyReportingUtilsTests.java index 35931e1baf9c..2cf36b309f4a 100644 --- a/platform-tests/src/test/java/org/junit/platform/reporting/legacy/LegacyReportingUtilsTests.java +++ b/platform-tests/src/test/java/org/junit/platform/reporting/legacy/LegacyReportingUtilsTests.java @@ -16,7 +16,6 @@ import java.util.Set; import org.junit.jupiter.api.Test; -import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestSource; import org.junit.platform.engine.UniqueId; @@ -72,13 +71,13 @@ void legacyReportingClassNameForDescendantOfTestIdentifierWithClassSourceIsClass } private String getClassName(UniqueId uniqueId) { - var testPlan = TestPlan.from(Set.of(engineDescriptor), mock(ConfigurationParameters.class)); + var testPlan = TestPlan.from(Set.of(engineDescriptor), mock()); return LegacyReportingUtils.getClassName(testPlan, testPlan.getTestIdentifier(uniqueId)); } @SuppressWarnings("deprecation") private String getClassNameFromOldLocation(UniqueId uniqueId) { - var testPlan = TestPlan.from(Set.of(engineDescriptor), mock(ConfigurationParameters.class)); + var testPlan = TestPlan.from(Set.of(engineDescriptor), mock()); return org.junit.platform.launcher.listeners.LegacyReportingUtils.getClassName(testPlan, testPlan.getTestIdentifier(uniqueId)); } diff --git a/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListenerTests.java b/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListenerTests.java index a0bcf137d122..1ae505f8ba54 100644 --- a/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListenerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/LegacyXmlReportGeneratingListenerTests.java @@ -42,7 +42,6 @@ import org.joox.Match; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import org.junit.platform.engine.ConfigurationParameters; import org.junit.platform.engine.TestEngine; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.reporting.ReportEntry; @@ -370,7 +369,7 @@ void printsExceptionWhenReportsDirCannotBeCreated() throws Exception { var out = new StringWriter(); var listener = new LegacyXmlReportGeneratingListener(reportsDir, new PrintWriter(out)); - listener.testPlanExecutionStarted(TestPlan.from(Set.of(), mock(ConfigurationParameters.class))); + listener.testPlanExecutionStarted(TestPlan.from(Set.of(), mock())); assertThat(out.toString()).containsSubsequence("Could not create reports directory", "FileAlreadyExistsException", "at "); @@ -386,7 +385,7 @@ void printsExceptionWhenReportCouldNotBeWritten() throws Exception { var out = new StringWriter(); var listener = new LegacyXmlReportGeneratingListener(tempDirectory, new PrintWriter(out)); - listener.testPlanExecutionStarted(TestPlan.from(Set.of(engineDescriptor), mock(ConfigurationParameters.class))); + listener.testPlanExecutionStarted(TestPlan.from(Set.of(engineDescriptor), mock())); listener.executionFinished(TestIdentifier.from(engineDescriptor), successful()); assertThat(out.toString()).containsSubsequence("Could not write XML report", "Exception", "at "); @@ -397,7 +396,7 @@ void writesReportEntriesToSystemOutElement() throws Exception { var engineDescriptor = new EngineDescriptor(UniqueId.forEngine("engine"), "Engine"); var childUniqueId = UniqueId.root("child", "test"); engineDescriptor.addChild(new TestDescriptorStub(childUniqueId, "test")); - var testPlan = TestPlan.from(Set.of(engineDescriptor), mock(ConfigurationParameters.class)); + var testPlan = TestPlan.from(Set.of(engineDescriptor), mock()); var out = new StringWriter(); var listener = new LegacyXmlReportGeneratingListener(tempDirectory, new PrintWriter(out)); diff --git a/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportDataTests.java b/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportDataTests.java index 65fd5acd0d92..fb88bc9f872b 100644 --- a/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportDataTests.java +++ b/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportDataTests.java @@ -30,7 +30,7 @@ */ class XmlReportDataTests { - private final ConfigurationParameters configParams = mock(ConfigurationParameters.class); + private final ConfigurationParameters configParams = mock(); @Test void resultsOfTestIdentifierWithoutAnyReportedEventsAreEmpty() { diff --git a/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportWriterTests.java b/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportWriterTests.java index 4c278dc6b2fa..8487afb1bceb 100644 --- a/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportWriterTests.java +++ b/platform-tests/src/test/java/org/junit/platform/reporting/legacy/xml/XmlReportWriterTests.java @@ -48,7 +48,7 @@ */ class XmlReportWriterTests { - private final ConfigurationParameters configParams = mock(ConfigurationParameters.class); + private final ConfigurationParameters configParams = mock(); private EngineDescriptor engineDescriptor = new EngineDescriptor(UniqueId.forEngine("engine"), "Engine"); diff --git a/platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java b/platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java index 30bdb61aa671..a515e6dd2990 100644 --- a/platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java +++ b/platform-tests/src/test/java/org/junit/platform/runner/JUnitPlatformRunnerTests.java @@ -465,7 +465,7 @@ void convertsTestIdentifiersIntoDescriptions() { TestDescriptor container2 = new TestDescriptorStub(UniqueId.root("root", "container2"), "container2"); container2.addChild(new TestDescriptorStub(UniqueId.root("root", "test2a"), "test2a")); container2.addChild(new TestDescriptorStub(UniqueId.root("root", "test2b"), "test2b")); - var testPlan = TestPlan.from(List.of(container1, container2), mock(ConfigurationParameters.class)); + var testPlan = TestPlan.from(List.of(container1, container2), mock()); var launcher = mock(Launcher.class); when(launcher.discover(any())).thenReturn(testPlan); @@ -502,7 +502,7 @@ private static void assertExcludes(Filter filter, T excluded) { @Nested class Filtering { - private final ConfigurationParameters configParams = mock(ConfigurationParameters.class); + private final ConfigurationParameters configParams = mock(); @Test void appliesFilter() throws Exception { @@ -777,8 +777,7 @@ private TestDescriptor testDescriptorWithTags(String... tag) { private LauncherDiscoveryRequest instantiateRunnerAndCaptureGeneratedRequest(Class testClass) { var launcher = mock(Launcher.class); var captor = ArgumentCaptor.forClass(LauncherDiscoveryRequest.class); - when(launcher.discover(captor.capture())).thenReturn( - TestPlan.from(Set.of(), mock(ConfigurationParameters.class))); + when(launcher.discover(captor.capture())).thenReturn(TestPlan.from(Set.of(), mock())); new JUnitPlatform(testClass, launcher); From b732a2bd05fe2a0a3a5ff01bdf6ad241a0c9434c Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 23 Jan 2023 17:17:24 +0100 Subject: [PATCH 16/25] Fix issues with @MethodSource local factory method lookups Prior to this commit, parameters were not validated in local @MethodSource factory methods which lead to incorrect configuration being silently ignored or confusing error messages when the specified factory method was overloaded. In addition, the syntax for local @MethodSource factory methods did not support canonical array names. This commit addresses these issues by treating local factory method resolution the same as the existing support for resolving a fully qualified method name for a factory method. These changes make the recently introduced parseQualifiedMethodName() method in ReflectionUtils obsolete. This commit therefore removes that method as well. Closes #3130 Closes #3131 (cherry picked from commit a0eb8e2bd9aa00445d442f0ea46e37551728ab83) --- .../provider/MethodArgumentsProvider.java | 88 +++---- .../MethodArgumentsProviderTests.java | 239 ++++++++++++++---- .../commons/util/ReflectionUtils.java | 43 +--- .../commons/util/ReflectionUtilsTests.java | 21 -- 4 files changed, 242 insertions(+), 149 deletions(-) diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java index a02649c3c3e4..638f33b19bb5 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java @@ -12,7 +12,6 @@ import static java.lang.String.format; import static java.util.Arrays.stream; -import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; import static org.junit.jupiter.params.provider.Arguments.arguments; import static org.junit.platform.commons.util.AnnotationUtils.isAnnotated; @@ -48,25 +47,33 @@ public void accept(MethodSource annotation) { @Override public Stream provideArguments(ExtensionContext context) { + Class testClass = context.getRequiredTestClass(); + Method testMethod = context.getRequiredTestMethod(); Object testInstance = context.getTestInstance().orElse(null); // @formatter:off return stream(this.methodNames) - .map(factoryMethodName -> getFactoryMethod(context, factoryMethodName)) + .map(factoryMethodName -> getFactoryMethod(testClass, testMethod, factoryMethodName)) .map(factoryMethod -> context.getExecutableInvoker().invoke(factoryMethod, testInstance)) .flatMap(CollectionUtils::toStream) .map(MethodArgumentsProvider::toArguments); // @formatter:on } - private Method getFactoryMethod(ExtensionContext context, String factoryMethodName) { - Method testMethod = context.getRequiredTestMethod(); - if (StringUtils.isBlank(factoryMethodName)) { - factoryMethodName = testMethod.getName(); + private Method getFactoryMethod(Class testClass, Method testMethod, String factoryMethodName) { + if (!StringUtils.isBlank(factoryMethodName)) { + if (looksLikeAFullyQualifiedMethodName(factoryMethodName)) { + return getFactoryMethodByFullyQualifiedName(factoryMethodName); + } + else if (looksLikeALocalQualifiedMethodName(factoryMethodName)) { + return getFactoryMethodByFullyQualifiedName(testClass.getName() + "#" + factoryMethodName); + } } - if (looksLikeAFullyQualifiedMethodName(factoryMethodName)) { - return getFactoryMethodByFullyQualifiedName(factoryMethodName); + else { + // User did not provide a factory method name, so we search for a + // factory method with the same name as the parameterized test method. + factoryMethodName = testMethod.getName(); } - return getFactoryMethodBySimpleOrQualifiedName(context.getRequiredTestClass(), testMethod, factoryMethodName); + return findFactoryMethodBySimpleName(testClass, testMethod, factoryMethodName); } private static boolean looksLikeAFullyQualifiedMethodName(String factoryMethodName) { @@ -89,6 +96,18 @@ private static boolean looksLikeAFullyQualifiedMethodName(String factoryMethodNa return true; } + private static boolean looksLikeALocalQualifiedMethodName(String factoryMethodName) { + // This method is intended to be called after looksLikeAFullyQualifiedMethodName() + // and therefore does not check for the absence of '#' and does not reason about + // the presence or absence of a fully qualified class name. + if (factoryMethodName.endsWith("()")) { + return true; + } + int indexOfLastOpeningParenthesis = factoryMethodName.lastIndexOf('('); + return (indexOfLastOpeningParenthesis > 0) + && (indexOfLastOpeningParenthesis < factoryMethodName.lastIndexOf(')')); + } + private Method getFactoryMethodByFullyQualifiedName(String fullyQualifiedMethodName) { String[] methodParts = ReflectionUtils.parseFullyQualifiedMethodName(fullyQualifiedMethodName); String className = methodParts[0]; @@ -100,33 +119,17 @@ private Method getFactoryMethodByFullyQualifiedName(String fullyQualifiedMethodN methodParameters, className))); } - private Method getFactoryMethodBySimpleOrQualifiedName(Class testClass, Method testMethod, - String simpleOrQualifiedMethodName) { - String[] methodParts = ReflectionUtils.parseQualifiedMethodName(simpleOrQualifiedMethodName); - String methodSimpleName = methodParts[0]; - String methodParameters = methodParts[1]; - - List factoryMethods = findFactoryMethodsBySimpleName(testClass, testMethod, methodSimpleName); - if (factoryMethods.size() == 1) { - return factoryMethods.get(0); - } - - List exactMatches = filterFactoryMethodsWithMatchingParameters(factoryMethods, - simpleOrQualifiedMethodName, methodParameters); - Preconditions.condition(exactMatches.size() == 1, - () -> format("%d factory methods named [%s] were found in class [%s]: %s", factoryMethods.size(), - simpleOrQualifiedMethodName, testClass.getName(), factoryMethods)); - return exactMatches.get(0); - } - /** * Find all methods in the given {@code testClass} with the desired {@code factoryMethodName} * which have return types that can be converted to a {@link Stream}, ignoring the * {@code testMethod} itself as well as any {@code @Test}, {@code @TestTemplate}, * or {@code @TestFactory} methods with the same name. + * @return the factory method, if found + * @throws org.junit.platform.commons.PreconditionViolationException if the + * factory method was not found or if multiple competing factory methods with + * the same name were found */ - private List findFactoryMethodsBySimpleName(Class testClass, Method testMethod, - String factoryMethodName) { + private Method findFactoryMethodBySimpleName(Class testClass, Method testMethod, String factoryMethodName) { Predicate isCandidate = candidate -> factoryMethodName.equals(candidate.getName()) && !testMethod.equals(candidate); List candidates = ReflectionUtils.findMethods(testClass, isCandidate); @@ -147,27 +150,10 @@ private List findFactoryMethodsBySimpleName(Class testClass, Method t // Otherwise, report that we didn't find anything. return format("Could not find factory method [%s] in class [%s]", factoryMethodName, testClass.getName()); }); - return factoryMethods; - } - - private static List filterFactoryMethodsWithMatchingParameters(List factoryMethods, - String factoryMethodName, String factoryMethodParameters) { - - if (!factoryMethodName.endsWith(")")) { - // If parameters are not specified, nothing is filtered. - return factoryMethods; - } - - // Compare against canonical parameter list, ignoring whitespace. - String parameterList = factoryMethodParameters.replaceAll("\\s+", ""); - Predicate hasRequiredParameters = method -> { - if (parameterList.isEmpty()) { - return method.getParameterCount() == 0; - } - return parameterList.equals(stream(method.getParameterTypes()).map(Class::getName).collect(joining(","))); - }; - - return factoryMethods.stream().filter(hasRequiredParameters).collect(toList()); + Preconditions.condition(factoryMethods.size() == 1, + () -> format("%d factory methods named [%s] were found in class [%s]: %s", factoryMethods.size(), + factoryMethodName, testClass.getName(), factoryMethods)); + return factoryMethods.get(0); } private boolean isTestMethod(Method candidate) { diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java index 9d05eb9ac07d..281670a4435f 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java @@ -14,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.engine.extension.MutableExtensionRegistry.createRegistryWithDefaultExtensions; import static org.junit.jupiter.params.provider.MethodArgumentsProviderTests.DefaultFactoryMethodNameTestCase.TEST_METHOD; +import static org.junit.platform.commons.util.ReflectionUtils.findMethod; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -23,6 +24,7 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.LongStream; @@ -34,7 +36,6 @@ 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.engine.config.JupiterConfiguration; import org.junit.jupiter.engine.execution.DefaultExecutableInvoker; import org.junit.jupiter.engine.extension.MutableExtensionRegistry; import org.junit.jupiter.params.ParameterizedTest; @@ -208,9 +209,9 @@ void providesArgumentsFromNonStaticFactoryMethodWhenStaticIsNotRequired() { } @Test - void providesArgumentsUsingDefaultFactoryMethodName() throws Exception { + void providesArgumentsUsingDefaultFactoryMethodName() { Class testClass = DefaultFactoryMethodNameTestCase.class; - var testMethod = testClass.getDeclaredMethod(TEST_METHOD, String.class); + var testMethod = findMethod(testClass, TEST_METHOD, String.class).get(); var arguments = provideArguments(testClass, testMethod, false, ""); assertThat(arguments).containsExactly(array("foo"), array("bar")); @@ -364,31 +365,34 @@ void providesArgumentsUsing2dObjectArray() { @Nested class ParameterResolution { + private final Method testMethod = findMethod(TestCase.class, "test").get(); + @BeforeEach void registerParameterResolver() { - JupiterConfiguration configuration = mock(); - extensionRegistry = createRegistryWithDefaultExtensions(configuration); + extensionRegistry = createRegistryWithDefaultExtensions(mock()); extensionRegistry.registerExtension(StringResolver.class); + extensionRegistry.registerExtension(StringArrayResolver.class); + extensionRegistry.registerExtension(IntArrayResolver.class); } @Test - void providesArgumentsUsingDefaultFactoryMethodWithParameter() throws Exception { - Class testClass = TestCase.class; - var testMethod = testClass.getDeclaredMethod("overloadedStringStreamProvider", Object.class); - var arguments = provideArguments(testClass, testMethod, false, ""); + void providesArgumentsInferringDefaultFactoryMethodThatAcceptsArgument() { + Method testMethod = findMethod(TestCase.class, "overloadedStringStreamProvider", Object.class).get(); + String factoryMethodName = ""; // signals to use default + var arguments = provideArguments(testMethod, factoryMethodName); assertThat(arguments).containsExactly(array("foo!"), array("bar!")); } @Test - void providesArgumentsUsingFactoryMethodWithParameter() { + void providesArgumentsUsingSimpleNameForFactoryMethodThatAcceptsArgumentWithoutSpecifyingParameterList() { var arguments = provideArguments("stringStreamProviderWithParameter"); assertThat(arguments).containsExactly(array("foo!"), array("bar!")); } @Test - void providesArgumentsUsingFullyQualifiedNameWithParameter() { + void providesArgumentsUsingFullyQualifiedNameSpecifyingParameter() { var arguments = provideArguments( TestCase.class.getName() + "#stringStreamProviderWithParameter(java.lang.String)"); @@ -396,66 +400,170 @@ void providesArgumentsUsingFullyQualifiedNameWithParameter() { } @Test - void providesArgumentsUsingSimpleNameWithoutParameter() { - var arguments = provideArguments("stringStreamProviderWithOrWithoutParameter()"); + void providesArgumentsUsingLocalQualifiedNameSpecifyingParameter() { + var arguments = provideArguments(testMethod, "stringStreamProviderWithParameter(java.lang.String)"); + + assertThat(arguments).containsExactly(array("foo!"), array("bar!")); + } + + @Test + void providesArgumentsUsingFullyQualifiedNameForOverloadedFactoryMethodSpecifyingEmptyParameterList() { + var arguments = provideArguments( + TestCase.class.getName() + "#stringStreamProviderWithOrWithoutParameter()"); assertThat(arguments).containsExactly(array("foo"), array("bar")); } @Test - void providesArgumentsUsingSimpleNameWithParameter() { - var arguments = provideArguments("stringStreamProviderWithOrWithoutParameter(java.lang.String)"); + void providesArgumentsUsingLocalQualifiedNameForOverloadedFactoryMethodSpecifyingEmptyParameterList() { + var arguments = provideArguments(this.testMethod, "stringStreamProviderWithOrWithoutParameter()"); + + assertThat(arguments).containsExactly(array("foo"), array("bar")); + } + + @Test + void providesArgumentsUsingFullyQualifiedNameForOverloadedFactoryMethodSpecifyingParameter() { + var arguments = provideArguments( + TestCase.class.getName() + "#stringStreamProviderWithOrWithoutParameter(java.lang.String)"); assertThat(arguments).containsExactly(array("foo!"), array("bar!")); } - @ParameterizedTest - @ValueSource(strings = { "java.lang.String,java.lang.String", "java.lang.String, java.lang.String", - "java.lang.String, java.lang.String" }) - void providesArgumentsUsingSimpleNameWithMultipleParameters(String params) { - var arguments = provideArguments("stringStreamProviderWithOrWithoutParameter(" + params + ")"); - assertThat(arguments).containsExactly(array("foo!!"), array("bar!!")); + @Test + void providesArgumentsUsingLocalQualifiedNameForOverloadedFactoryMethodSpecifyingParameter() { + var arguments = provideArguments(testMethod, + "stringStreamProviderWithOrWithoutParameter(java.lang.String)"); + + assertThat(arguments).containsExactly(array("foo!"), array("bar!")); } @Test - void throwsExceptionWhenSeveralFactoryMethodsWithSameNameAreAvailable() { - var exception = assertThrows(PreconditionViolationException.class, - () -> provideArguments("stringStreamProviderWithOrWithoutParameter").toArray()); + void failsToProvideArgumentsUsingFullyQualifiedNameSpecifyingInvalidParameterType() { + String method = TestCase.class.getName() + "#stringStreamProviderWithParameter(example.FooBar)"; + var exception = assertThrows(JUnitException.class, () -> provideArguments(method).toArray()); - assertThat(exception.getMessage())// - .startsWith("3 factory methods named [stringStreamProviderWithOrWithoutParameter] were found in " - + "class [org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase]: ")// - .contains("stringStreamProviderWithOrWithoutParameter()", - "stringStreamProviderWithOrWithoutParameter(java.lang.String)", - "stringStreamProviderWithOrWithoutParameter(java.lang.String,java.lang.String)"); + assertThat(exception).hasMessage(""" + Failed to load parameter type [example.FooBar] for method [stringStreamProviderWithParameter] \ + in class [org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase]."""); } @Test - void providesArgumentsUsingFactoryMethodSelectedViaFullyQualifiedNameWithParameter() { - var arguments = provideArguments( - TestCase.class.getName() + "#stringStreamProviderWithOrWithoutParameter(java.lang.String)"); + void failsToProvideArgumentsUsingLocalQualifiedNameSpecifyingInvalidParameterType() { + var method = "stringStreamProviderWithParameter(example.FooBar)"; + var exception = assertThrows(JUnitException.class, + () -> provideArguments(this.testMethod, method).toArray()); - assertThat(arguments).containsExactly(array("foo!"), array("bar!")); + assertThat(exception).hasMessage(""" + Failed to load parameter type [example.FooBar] for method [stringStreamProviderWithParameter] \ + in class [org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase]."""); + } + + @Test + void failsToProvideArgumentsUsingFullyQualifiedNameSpecifyingIncorrectParameterType() { + String method = TestCase.class.getName() + "#stringStreamProviderWithParameter(java.lang.Integer)"; + var exception = assertThrows(JUnitException.class, () -> provideArguments(method).toArray()); + + assertThat(exception).hasMessage(""" + Could not find factory method [stringStreamProviderWithParameter(java.lang.Integer)] in \ + class [org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase]"""); + } + + @Test + void failsToProvideArgumentsUsingLocalQualifiedNameSpecifyingIncorrectParameterType() { + var method = "stringStreamProviderWithParameter(java.lang.Integer)"; + var exception = assertThrows(JUnitException.class, + () -> provideArguments(this.testMethod, method).toArray()); + + assertThat(exception).hasMessage(""" + Could not find factory method [stringStreamProviderWithParameter(java.lang.Integer)] in \ + class [org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase]"""); + } + + @ParameterizedTest + @ValueSource(strings = { + "org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase#stringStreamProviderWithArrayParameter(java.lang.String[])", + "org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase#stringStreamProviderWithArrayParameter([Ljava.lang.String;)", }) + void providesArgumentsUsingFullyQualifiedNameSpecifyingObjectArrayParameter(String method) { + var arguments = provideArguments(method); + + assertThat(arguments).containsExactly(array("foo :)"), array("bar :)")); + } + + @ParameterizedTest + @ValueSource(strings = { // + "stringStreamProviderWithArrayParameter(java.lang.String[])", + "stringStreamProviderWithArrayParameter([Ljava.lang.String;)" }) + void providesArgumentsUsingLocalQualifiedNameSpecifyingObjectArrayParameter(String method) { + var arguments = provideArguments(this.testMethod, method); + + assertThat(arguments).containsExactly(array("foo :)"), array("bar :)")); + } + + @ParameterizedTest + @ValueSource(strings = { + "org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase#stringStreamProviderWithArrayParameter(int[])", + "org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase#stringStreamProviderWithArrayParameter([I)", }) + void providesArgumentsUsingFullyQualifiedNameSpecifyingPrimitiveArrayParameter(String method) { + var arguments = provideArguments(method); + + assertThat(arguments).containsExactly(array("foo 42"), array("bar 42")); + } + + @ParameterizedTest + @ValueSource(strings = { // + "stringStreamProviderWithArrayParameter(int[])", // + "stringStreamProviderWithArrayParameter([I)" }) + void providesArgumentsUsingLocalQualifiedNameSpecifyingPrimitiveArrayParameter(String method) { + var arguments = provideArguments(this.testMethod, method); + + assertThat(arguments).containsExactly(array("foo 42"), array("bar 42")); } @ParameterizedTest @ValueSource(strings = { "java.lang.String,java.lang.String", "java.lang.String, java.lang.String", "java.lang.String, java.lang.String" }) - void providesArgumentsUsingFactoryMethodSelectedViaFullyQualifiedNameWithMultipleParameters(String params) { - var arguments = provideArguments( - TestCase.class.getName() + "#stringStreamProviderWithOrWithoutParameter(" + params + ")"); + void providesArgumentsUsingFullyQualifiedNameSpecifyingMultipleParameters(String params) { + var method = TestCase.class.getName() + "#stringStreamProviderWithOrWithoutParameter(" + params + ")"; + var arguments = provideArguments(method); assertThat(arguments).containsExactly(array("foo!!"), array("bar!!")); } + @ParameterizedTest + @ValueSource(strings = { "java.lang.String,java.lang.String", "java.lang.String, java.lang.String", + "java.lang.String, java.lang.String" }) + void providesArgumentsUsingLocalQualifiedNameSpecifyingMultipleParameters(String params) { + var arguments = provideArguments(this.testMethod, + "stringStreamProviderWithOrWithoutParameter(" + params + ")"); + + assertThat(arguments).containsExactly(array("foo!!"), array("bar!!")); + } + + /** + * In contrast to {@link #failsToProvideArgumentsUsingLocalQualifiedNameForOverloadedFactoryMethodWhenParameterListIsNotSpecified()}, + * using the fully qualified method name without specifying the parameter list "selects" + * the overloaded method that accepts zero arguments. + */ @Test - void providesArgumentsUsingFactoryMethodSelectedViaFullyQualifiedNameWithoutParameter() { - var arguments = provideArguments( - TestCase.class.getName() + "#stringStreamProviderWithOrWithoutParameter()"); + void providesArgumentsUsingFullyQualifiedNameForOverloadedFactoryMethodWhenParameterListIsNotSpecified() { + var arguments = provideArguments(TestCase.class.getName() + "#stringStreamProviderWithOrWithoutParameter"); assertThat(arguments).containsExactly(array("foo"), array("bar")); } + @Test + void failsToProvideArgumentsUsingLocalQualifiedNameForOverloadedFactoryMethodWhenParameterListIsNotSpecified() { + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments("stringStreamProviderWithOrWithoutParameter").toArray()); + + assertThat(exception.getMessage())// + .startsWith("3 factory methods named [stringStreamProviderWithOrWithoutParameter] were found in " + + "class [org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase]: ")// + .contains("stringStreamProviderWithOrWithoutParameter()", + "stringStreamProviderWithOrWithoutParameter(java.lang.String)", + "stringStreamProviderWithOrWithoutParameter(java.lang.String,java.lang.String)"); + } + } // ------------------------------------------------------------------------- @@ -464,12 +572,16 @@ private static Object[] array(Object... objects) { return objects; } - private Stream provideArguments(String... methodNames) { - return provideArguments(TestCase.class, null, false, methodNames); + private Stream provideArguments(String... factoryMethodNames) { + return provideArguments(TestCase.class, null, false, factoryMethodNames); + } + + private Stream provideArguments(Method testMethod, String factoryMethodName) { + return provideArguments(TestCase.class, testMethod, false, factoryMethodName); } private Stream provideArguments(Class testClass, Method testMethod, boolean allowNonStaticMethod, - String... methodNames) { + String... factoryMethodNames) { if (testMethod == null) { try { @@ -483,7 +595,7 @@ private Stream provideArguments(Class testClass, Method testMethod, var methodSource = mock(MethodSource.class); - when(methodSource.value()).thenReturn(methodNames); + when(methodSource.value()).thenReturn(factoryMethodNames); var extensionContext = mock(ExtensionContext.class); when(extensionContext.getTestClass()).thenReturn(Optional.of(testClass)); @@ -518,6 +630,9 @@ void testDefaultFactoryMethodName(String param) { static class TestCase { + void test() { + } + // --- Invalid --------------------------------------------------------- static Object providerWithIllegalReturnType() { @@ -534,6 +649,16 @@ static Stream stringStreamProviderWithParameter(String parameter) { return Stream.of("foo" + parameter, "bar" + parameter); } + static Stream stringStreamProviderWithArrayParameter(String[] parameter) { + String suffix = Arrays.stream(parameter).collect(Collectors.joining()); + return Stream.of("foo " + suffix, "bar " + suffix); + } + + static Stream stringStreamProviderWithArrayParameter(int[] parameter) { + return stringStreamProviderWithArrayParameter( + Arrays.stream(parameter).mapToObj(String::valueOf).toArray(String[]::new)); + } + static Stream stringStreamProviderWithOrWithoutParameter() { return stringStreamProvider(); } @@ -698,4 +823,30 @@ public Object resolveParameter(ParameterContext parameterContext, ExtensionConte } } + static class StringArrayResolver implements ParameterResolver { + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return parameterContext.getParameter().getType() == String[].class; + } + + @Override + public String[] resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return new String[] { ":", ")" }; + } + } + + static class IntArrayResolver implements ParameterResolver { + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return parameterContext.getParameter().getType() == int[].class; + } + + @Override + public int[] resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return new int[] { 4, 2 }; + } + } + } 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 9b2fb05d8fb0..c20c93b9c2e4 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 @@ -909,44 +909,21 @@ public static String[] parseFullyQualifiedMethodName(String fullyQualifiedMethod + "and then the method name, optionally followed by a parameter list enclosed in parentheses."); String className = fullyQualifiedMethodName.substring(0, indexOfFirstHashtag); - String qualifiedMethodName = fullyQualifiedMethodName.substring(indexOfFirstHashtag + 1); - String[] methodPart = parseQualifiedMethodName(qualifiedMethodName); - - return new String[] { className, methodPart[0], methodPart[1] }; - } - - /** - * Parse the supplied method name into a 2-element {@code String[]} with - * the following content. - * - *

    - *
  • index {@code 0}: the name of the method
  • - *
  • index {@code 1}: a comma-separated list of parameter types, or a - * blank string if the method does not declare any formal parameters
  • - *
- * - * @param qualifiedMethodName a qualified method name, never {@code null} or blank - * @return a 2-element array of strings containing the parsed values - */ - @API(status = INTERNAL, since = "1.9.2") - public static String[] parseQualifiedMethodName(String qualifiedMethodName) { - String methodName = qualifiedMethodName; + String methodPart = fullyQualifiedMethodName.substring(indexOfFirstHashtag + 1); + String methodName = methodPart; String methodParameters = ""; - if (qualifiedMethodName.endsWith("()")) { - methodName = qualifiedMethodName.substring(0, qualifiedMethodName.length() - 2); + if (methodPart.endsWith("()")) { + methodName = methodPart.substring(0, methodPart.length() - 2); } - else if (qualifiedMethodName.endsWith(")")) { - int indexOfLastOpeningParenthesis = qualifiedMethodName.lastIndexOf('('); - if ((indexOfLastOpeningParenthesis > 0) - && (indexOfLastOpeningParenthesis < qualifiedMethodName.length() - 1)) { - methodName = qualifiedMethodName.substring(0, indexOfLastOpeningParenthesis); - methodParameters = qualifiedMethodName.substring(indexOfLastOpeningParenthesis + 1, - qualifiedMethodName.length() - 1); + else if (methodPart.endsWith(")")) { + int indexOfLastOpeningParenthesis = methodPart.lastIndexOf('('); + if ((indexOfLastOpeningParenthesis > 0) && (indexOfLastOpeningParenthesis < methodPart.length() - 1)) { + methodName = methodPart.substring(0, indexOfLastOpeningParenthesis); + methodParameters = methodPart.substring(indexOfLastOpeningParenthesis + 1, methodPart.length() - 1); } } - - return new String[] { methodName, methodParameters }; + return new String[] { className, methodName, methodParameters }; } /** 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 a9e3c4ece463..d667bce7767b 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 @@ -55,8 +55,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.fixtures.TrackLogRecords; import org.junit.jupiter.api.io.TempDir; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.junit.platform.commons.JUnitException; import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.logging.LogRecordListener; @@ -702,25 +700,6 @@ void parseFullyQualifiedMethodNameForMethodWithMultipleParameters() { .containsExactly("com.example.Test", "method", "int, java.lang.Object"); } - @ParameterizedTest - @ValueSource(strings = { "method", "method()" }) - void parseSimpleMethodNameForMethodWithoutParameters(String methodName) { - assertThat(ReflectionUtils.parseQualifiedMethodName(methodName))// - .containsExactly("method", ""); - } - - @Test - void parseSimpleMethodNameForMethodWithSingleParameter() { - assertThat(ReflectionUtils.parseQualifiedMethodName("method(java.lang.Object)"))// - .containsExactly("method", "java.lang.Object"); - } - - @Test - void parseSimpleMethodNameForMethodWithMultipleParameters() { - assertThat(ReflectionUtils.parseQualifiedMethodName("method(int, java.lang.Object)"))// - .containsExactly("method", "int, java.lang.Object"); - } - @Test @SuppressWarnings("deprecation") void getOutermostInstancePreconditions() { From f6f1afff075db92010871e841cc756ad19dc720a Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Sat, 22 Apr 2023 21:58:04 +0200 Subject: [PATCH 17/25] Move release notes entry for #3130 to 5.9.3 --- .../docs/asciidoc/release-notes/release-notes-5.9.3.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc index 4e0da156e26f..0ec90b9e25e0 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc @@ -31,6 +31,15 @@ JUnit repository on GitHub. ==== Bug Fixes +* Parameter types for _local_ `@MethodSource` factory method names are now validated. For + example, `@MethodSource("myFactory(example.NonexistentType)")` will now result in an + exception stating that `example.NonexistentType` cannot be resolved to a valid type. +* The syntax for parameter types in _local_ `@MethodSource` factory method names now + supports canonical array names -- for example, you may now specify `int[]` as in + `@MethodSource("myFactory(int[])"` instead of the _binary_ name `[I` as in + `@MethodSource("myFactory([I)"` (which was already supported) and + `@MethodSource("myFactory(java.lang.String[])` instead of + `@MethodSource("myFactory([Ljava.lang.String;)`. * Exceptions thrown for undeletable files when cleaning up a temporary directory created via `@TempDir` now include the root cause. * Allow lifecycle methods to be declared as `private` again for backwards compatibility From 5b4a00046bbba4d2c5f9ea48cf59e598fee37c8a Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 23 Apr 2023 13:34:14 +0200 Subject: [PATCH 18/25] Polish 5.9.3 Release Notes --- .../asciidoc/release-notes/release-notes-5.9.3.adoc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc index 0ec90b9e25e0..8e4f71799f9b 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc @@ -40,10 +40,11 @@ JUnit repository on GitHub. `@MethodSource("myFactory([I)"` (which was already supported) and `@MethodSource("myFactory(java.lang.String[])` instead of `@MethodSource("myFactory([Ljava.lang.String;)`. -* Exceptions thrown for undeletable files when cleaning up a temporary directory created - via `@TempDir` now include the root cause. -* Allow lifecycle methods to be declared as `private` again for backwards compatibility - but document it as a discouraged practice. +* Exceptions thrown for files that cannot be deleted when cleaning up a temporary + directory created via `@TempDir` now include the root cause. +* Lifecycle methods are allowed to be declared as `private` again for backwards + compatibility; however, using `private` visibility for lifecycle methods is strongly + discouraged and will be disallowed in a future release. ==== Deprecations and Breaking Changes @@ -54,7 +55,7 @@ JUnit repository on GitHub. * ❓ -= [[release-notes-5.9.3-junit-vintage]] +[[release-notes-5.9.3-junit-vintage]] === JUnit Vintage ==== Bug Fixes From 82f1f4be2ff43b8d445f970ae8de659cab2022d5 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 22 Apr 2023 12:20:31 +0200 Subject: [PATCH 19/25] Treat overloaded local & external @MethodSource factory methods equally Prior to this commit, given overloaded @MethodSource factory methods, a local qualified method name (LQMN) was not treated the same as a fully-qualified method name (FQMN). Specifically, if the user provided a FQMN without specifying the parameter list, JUnit Jupiter would find the factory method that accepts zero arguments. Whereas, if the user provided an LQMN without specifying the parameter list, JUnit Jupiter would fail to find the factory method. This commit fixes that bug by reworking the internals of MethodArgumentsProvider so that overloaded local and external factory methods are looked up with the same semantics. The commit also improves diagnostics for failure to find a factory method specified via LQMN by falling back to the same lenient search semantics that are used to locate a "default" local factory method. Furthermore, this commit modifies the internals of MethodArgumentsProvider so that it consistently throws PreconditionViolationExceptions for user configuration errors. This commit also introduces additional tests for error use cases. See: #3130, #3131 Closes: #3266 --- .../release-notes/release-notes-5.9.3.adoc | 8 +- .../provider/MethodArgumentsProvider.java | 113 ++++--- .../jupiter/params/provider/MethodSource.java | 16 +- .../MethodArgumentsProviderTests.java | 288 +++++++++++++----- 4 files changed, 300 insertions(+), 125 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc index 8e4f71799f9b..cb4b0f1ec7a2 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc @@ -40,6 +40,9 @@ JUnit repository on GitHub. `@MethodSource("myFactory([I)"` (which was already supported) and `@MethodSource("myFactory(java.lang.String[])` instead of `@MethodSource("myFactory([Ljava.lang.String;)`. +* The search algorithm used to find `@MethodSource` factory methods now applies consistent + semantics for _local_ qualified method names and fully-qualified method names for + overloaded factory methods. * Exceptions thrown for files that cannot be deleted when cleaning up a temporary directory created via `@TempDir` now include the root cause. * Lifecycle methods are allowed to be declared as `private` again for backwards @@ -52,7 +55,10 @@ JUnit repository on GitHub. ==== New Features and Improvements -* ❓ +* The search algorithm used to find `@MethodSource` factory methods now falls back to + lenient search semantics when a factory method cannot be found by qualified name + (without a parameter list) and also provides better diagnostics when a unique factory + method cannot be found. [[release-notes-5.9.3-junit-vintage]] diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java index 638f33b19bb5..d9fdffab336f 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodArgumentsProvider.java @@ -28,6 +28,7 @@ import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.support.AnnotationConsumer; import org.junit.platform.commons.JUnitException; +import org.junit.platform.commons.PreconditionViolationException; import org.junit.platform.commons.util.CollectionUtils; import org.junit.platform.commons.util.Preconditions; import org.junit.platform.commons.util.ReflectionUtils; @@ -40,6 +41,9 @@ class MethodArgumentsProvider implements ArgumentsProvider, AnnotationConsumer isFactoryMethod = // + method -> isConvertibleToStream(method.getReturnType()) && !isTestMethod(method); + @Override public void accept(MethodSource annotation) { this.methodNames = annotation.value(); @@ -52,28 +56,37 @@ public Stream provideArguments(ExtensionContext context) { Object testInstance = context.getTestInstance().orElse(null); // @formatter:off return stream(this.methodNames) - .map(factoryMethodName -> getFactoryMethod(testClass, testMethod, factoryMethodName)) + .map(factoryMethodName -> findFactoryMethod(testClass, testMethod, factoryMethodName)) .map(factoryMethod -> context.getExecutableInvoker().invoke(factoryMethod, testInstance)) .flatMap(CollectionUtils::toStream) .map(MethodArgumentsProvider::toArguments); // @formatter:on } - private Method getFactoryMethod(Class testClass, Method testMethod, String factoryMethodName) { - if (!StringUtils.isBlank(factoryMethodName)) { - if (looksLikeAFullyQualifiedMethodName(factoryMethodName)) { - return getFactoryMethodByFullyQualifiedName(factoryMethodName); - } - else if (looksLikeALocalQualifiedMethodName(factoryMethodName)) { - return getFactoryMethodByFullyQualifiedName(testClass.getName() + "#" + factoryMethodName); - } - } - else { - // User did not provide a factory method name, so we search for a - // factory method with the same name as the parameterized test method. + private static Method findFactoryMethod(Class testClass, Method testMethod, String factoryMethodName) { + String originalFactoryMethodName = factoryMethodName; + + // If the user did not provide a factory method name, find a "default" local + // factory method with the same name as the parameterized test method. + if (StringUtils.isBlank(factoryMethodName)) { factoryMethodName = testMethod.getName(); + return findFactoryMethodBySimpleName(testClass, testMethod, factoryMethodName); } - return findFactoryMethodBySimpleName(testClass, testMethod, factoryMethodName); + + // Convert local factory method name to fully-qualified method name. + if (!looksLikeAFullyQualifiedMethodName(factoryMethodName)) { + factoryMethodName = testClass.getName() + "#" + factoryMethodName; + } + + // Find factory method using fully-qualified name. + Method factoryMethod = findFactoryMethodByFullyQualifiedName(testMethod, factoryMethodName); + + // Ensure factory method has a valid return type and is not a test method. + Preconditions.condition(isFactoryMethod.test(factoryMethod), () -> format( + "Could not find valid factory method [%s] for test class [%s] but found the following invalid candidate: %s", + originalFactoryMethodName, testClass.getName(), factoryMethod)); + + return factoryMethod; } private static boolean looksLikeAFullyQualifiedMethodName(String factoryMethodName) { @@ -90,52 +103,54 @@ private static boolean looksLikeAFullyQualifiedMethodName(String factoryMethodNa return indexOfDot < indexOfOpeningParenthesis; } // If we get this far, we conclude the supplied factory method name "looks" - // like it was intended to be a fully qualified method name, even if the + // like it was intended to be a fully-qualified method name, even if the // syntax is invalid. We do this in order to provide better diagnostics for - // the user when a fully qualified method name is in fact invalid. + // the user when a fully-qualified method name is in fact invalid. return true; } - private static boolean looksLikeALocalQualifiedMethodName(String factoryMethodName) { - // This method is intended to be called after looksLikeAFullyQualifiedMethodName() - // and therefore does not check for the absence of '#' and does not reason about - // the presence or absence of a fully qualified class name. - if (factoryMethodName.endsWith("()")) { - return true; - } - int indexOfLastOpeningParenthesis = factoryMethodName.lastIndexOf('('); - return (indexOfLastOpeningParenthesis > 0) - && (indexOfLastOpeningParenthesis < factoryMethodName.lastIndexOf(')')); - } - - private Method getFactoryMethodByFullyQualifiedName(String fullyQualifiedMethodName) { + private static Method findFactoryMethodByFullyQualifiedName(Method testMethod, String fullyQualifiedMethodName) { String[] methodParts = ReflectionUtils.parseFullyQualifiedMethodName(fullyQualifiedMethodName); String className = methodParts[0]; String methodName = methodParts[1]; String methodParameters = methodParts[2]; + Class clazz = loadRequiredClass(className); + + // Attempt to find an exact match first. + Method factoryMethod = ReflectionUtils.findMethod(clazz, methodName, methodParameters).orElse(null); + if (factoryMethod != null) { + return factoryMethod; + } + + boolean explicitParameterListSpecified = // + StringUtils.isNotBlank(methodParameters) || fullyQualifiedMethodName.endsWith("()"); + + // If we didn't find an exact match but an explicit parameter list was specified, + // that's a user configuration error. + Preconditions.condition(!explicitParameterListSpecified, + () -> format("Could not find factory method [%s(%s)] in class [%s]", methodName, methodParameters, + className)); - return ReflectionUtils.findMethod(loadRequiredClass(className), methodName, methodParameters).orElseThrow( - () -> new JUnitException(format("Could not find factory method [%s(%s)] in class [%s]", methodName, - methodParameters, className))); + // Otherwise, fall back to the same lenient search semantics that are used + // to locate a "default" local factory method. + return findFactoryMethodBySimpleName(clazz, testMethod, methodName); } /** - * Find all methods in the given {@code testClass} with the desired {@code factoryMethodName} - * which have return types that can be converted to a {@link Stream}, ignoring the - * {@code testMethod} itself as well as any {@code @Test}, {@code @TestTemplate}, - * or {@code @TestFactory} methods with the same name. - * @return the factory method, if found - * @throws org.junit.platform.commons.PreconditionViolationException if the - * factory method was not found or if multiple competing factory methods with - * the same name were found + * Find the factory method by searching for all methods in the given {@code clazz} + * with the desired {@code factoryMethodName} which have return types that can be + * converted to a {@link Stream}, ignoring the {@code testMethod} itself as well + * as any {@code @Test}, {@code @TestTemplate}, or {@code @TestFactory} methods + * with the same name. + * @return the single factory method matching the search criteria + * @throws PreconditionViolationException if the factory method was not found or + * multiple competing factory methods with the same name were found */ - private Method findFactoryMethodBySimpleName(Class testClass, Method testMethod, String factoryMethodName) { + private static Method findFactoryMethodBySimpleName(Class clazz, Method testMethod, String factoryMethodName) { Predicate isCandidate = candidate -> factoryMethodName.equals(candidate.getName()) && !testMethod.equals(candidate); - List candidates = ReflectionUtils.findMethods(testClass, isCandidate); + List candidates = ReflectionUtils.findMethods(clazz, isCandidate); - Predicate isFactoryMethod = method -> isConvertibleToStream(method.getReturnType()) - && !isTestMethod(method); List factoryMethods = candidates.stream().filter(isFactoryMethod).collect(toList()); Preconditions.condition(factoryMethods.size() > 0, () -> { @@ -145,23 +160,23 @@ private Method findFactoryMethodBySimpleName(Class testClass, Method testMeth if (candidates.size() > 0) { return format( "Could not find valid factory method [%s] in class [%s] but found the following invalid candidates: %s", - factoryMethodName, testClass.getName(), candidates); + factoryMethodName, clazz.getName(), candidates); } // Otherwise, report that we didn't find anything. - return format("Could not find factory method [%s] in class [%s]", factoryMethodName, testClass.getName()); + return format("Could not find factory method [%s] in class [%s]", factoryMethodName, clazz.getName()); }); Preconditions.condition(factoryMethods.size() == 1, () -> format("%d factory methods named [%s] were found in class [%s]: %s", factoryMethods.size(), - factoryMethodName, testClass.getName(), factoryMethods)); + factoryMethodName, clazz.getName(), factoryMethods)); return factoryMethods.get(0); } - private boolean isTestMethod(Method candidate) { + private static boolean isTestMethod(Method candidate) { return isAnnotated(candidate, Test.class) || isAnnotated(candidate, TestTemplate.class) || isAnnotated(candidate, TestFactory.class); } - private Class loadRequiredClass(String className) { + private static Class loadRequiredClass(String className) { return ReflectionUtils.tryToLoadClass(className).getOrThrow( cause -> new JUnitException(format("Could not load class [%s]", className), cause)); } diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSource.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSource.java index 2d0ffe9eb8a5..94f6225fd53f 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSource.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/MethodSource.java @@ -110,12 +110,20 @@ * The names of factory methods within the test class or in external classes * to use as sources for arguments. * - *

Factory methods in external classes must be referenced by fully - * qualified method name — for example, - * {@code com.example.StringsProviders#blankStrings} or - * {@code com.example.TopLevelClass$NestedClass#classMethod} for a factory + *

Factory methods in external classes must be referenced by + * fully-qualified method name — for example, + * {@code "com.example.StringsProviders#blankStrings"} or + * {@code "com.example.TopLevelClass$NestedClass#classMethod"} for a factory * method in a static nested class. * + *

If a factory method accepts arguments that are provided by a + * {@link org.junit.jupiter.api.extension.ParameterResolver ParameterResolver}, + * you can supply the formal parameter list in the qualified method name to + * disambiguate between overloaded variants of the factory method. For example, + * {@code "blankStrings(int)"} for a local qualified method name or + * {@code "com.example.StringsProviders#blankStrings(int)"} for a fully-qualified + * method name. + * *

If no factory method names are declared, a method within the test class * that has the same name as the test method will be used as the factory * method by default. diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java index 281670a4435f..1bd49479bb06 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/provider/MethodArgumentsProviderTests.java @@ -13,7 +13,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.engine.extension.MutableExtensionRegistry.createRegistryWithDefaultExtensions; -import static org.junit.jupiter.params.provider.MethodArgumentsProviderTests.DefaultFactoryMethodNameTestCase.TEST_METHOD; import static org.junit.platform.commons.util.ReflectionUtils.findMethod; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; @@ -50,26 +49,6 @@ class MethodArgumentsProviderTests { private MutableExtensionRegistry extensionRegistry; - @Test - void throwsExceptionWhenFactoryMethodDoesNotExist() { - var exception = assertThrows(JUnitException.class, () -> provideArguments("unknownMethod").toArray()); - - assertThat(exception.getMessage()).isEqualTo( - "Could not find factory method [unknownMethod] in class [" + TestCase.class.getName() + "]"); - } - - @Test - void throwsExceptionForIllegalReturnType() { - var exception = assertThrows(PreconditionViolationException.class, - () -> provideArguments("providerWithIllegalReturnType").toArray()); - - assertThat(exception.getMessage())// - .containsSubsequence("Could not find valid factory method [providerWithIllegalReturnType] in class [", - TestCase.class.getName() + "]", // - "but found the following invalid candidates: ", // - "[static java.lang.Object org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase.providerWithIllegalReturnType()]"); - } - @Test void providesArgumentsUsingStream() { var arguments = provideArguments("stringStreamProvider"); @@ -195,7 +174,7 @@ void providesArgumentsUsingListOfObjectArrays() { @Test void throwsExceptionWhenNonStaticFactoryMethodIsReferencedAndStaticIsRequired() { - var exception = assertThrows(JUnitException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(NonStaticTestCase.class, null, false, "nonStaticStringStreamProvider").toArray()); assertThat(exception).hasMessageContaining("Cannot invoke non-static method"); @@ -210,8 +189,10 @@ void providesArgumentsFromNonStaticFactoryMethodWhenStaticIsNotRequired() { @Test void providesArgumentsUsingDefaultFactoryMethodName() { - Class testClass = DefaultFactoryMethodNameTestCase.class; - var testMethod = findMethod(testClass, TEST_METHOD, String.class).get(); + var testClass = DefaultFactoryMethodNameTestCase.class; + var methodName = "testDefaultFactoryMethodName"; + var testMethod = findMethod(testClass, methodName, String.class).get(); + var arguments = provideArguments(testClass, testMethod, false, ""); assertThat(arguments).containsExactly(array("foo"), array("bar")); @@ -246,35 +227,6 @@ void providesArgumentsUsingExternalAndInternalFactoryMethodsCombined() { assertThat(arguments).containsExactly(array("foo"), array("bar"), array("string1"), array("string2")); } - @Test - void throwsExceptionWhenClassForExternalFactoryMethodCannotBeLoaded() { - var exception = assertThrows(JUnitException.class, - () -> provideArguments("com.example.NonExistentExternalFactoryMethods#stringsProvider").toArray()); - - assertThat(exception.getMessage()).isEqualTo( - "Could not load class [com.example.NonExistentExternalFactoryMethods]"); - } - - @Test - void throwsExceptionWhenExternalFactoryMethodCannotBeFound() { - var exception = assertThrows(JUnitException.class, - () -> provideArguments(ExternalFactoryMethods.class.getName() + "#nonExistentMethod").toArray()); - - assertThat(exception.getMessage()).isEqualTo("Could not find factory method [nonExistentMethod()] in class [" - + ExternalFactoryMethods.class.getName() + "]"); - } - - @Test - void throwsExceptionWhenFullyQualifiedMethodNameIsInvalid() { - var exception = assertThrows(JUnitException.class, - () -> provideArguments(ExternalFactoryMethods.class.getName() + ".wrongSyntax").toArray()); - - assertThat(exception.getMessage()).isEqualTo( - "[" + ExternalFactoryMethods.class.getName() + ".wrongSyntax] is not a valid fully qualified method name: " - + "it must start with a fully qualified class name followed by a '#' and then the method name, " - + "optionally followed by a parameter list enclosed in parentheses."); - } - @Nested class PrimitiveArrays { @@ -391,6 +343,13 @@ void providesArgumentsUsingSimpleNameForFactoryMethodThatAcceptsArgumentWithoutS assertThat(arguments).containsExactly(array("foo!"), array("bar!")); } + @Test + void providesArgumentsUsingFullyQualifiedNameForFactoryMethodThatAcceptsArgumentWithoutSpecifyingParameterList() { + var arguments = provideArguments(TestCase.class.getName() + "#stringStreamProviderWithParameter"); + + assertThat(arguments).containsExactly(array("foo!"), array("bar!")); + } + @Test void providesArgumentsUsingFullyQualifiedNameSpecifyingParameter() { var arguments = provideArguments( @@ -461,7 +420,8 @@ in class [org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCas @Test void failsToProvideArgumentsUsingFullyQualifiedNameSpecifyingIncorrectParameterType() { String method = TestCase.class.getName() + "#stringStreamProviderWithParameter(java.lang.Integer)"; - var exception = assertThrows(JUnitException.class, () -> provideArguments(method).toArray()); + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(method).toArray()); assertThat(exception).hasMessage(""" Could not find factory method [stringStreamProviderWithParameter(java.lang.Integer)] in \ @@ -471,7 +431,7 @@ class [org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase]" @Test void failsToProvideArgumentsUsingLocalQualifiedNameSpecifyingIncorrectParameterType() { var method = "stringStreamProviderWithParameter(java.lang.Integer)"; - var exception = assertThrows(JUnitException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(this.testMethod, method).toArray()); assertThat(exception).hasMessage(""" @@ -539,11 +499,6 @@ void providesArgumentsUsingLocalQualifiedNameSpecifyingMultipleParameters(String assertThat(arguments).containsExactly(array("foo!!"), array("bar!!")); } - /** - * In contrast to {@link #failsToProvideArgumentsUsingLocalQualifiedNameForOverloadedFactoryMethodWhenParameterListIsNotSpecified()}, - * using the fully qualified method name without specifying the parameter list "selects" - * the overloaded method that accepts zero arguments. - */ @Test void providesArgumentsUsingFullyQualifiedNameForOverloadedFactoryMethodWhenParameterListIsNotSpecified() { var arguments = provideArguments(TestCase.class.getName() + "#stringStreamProviderWithOrWithoutParameter"); @@ -552,16 +507,160 @@ void providesArgumentsUsingFullyQualifiedNameForOverloadedFactoryMethodWhenParam } @Test - void failsToProvideArgumentsUsingLocalQualifiedNameForOverloadedFactoryMethodWhenParameterListIsNotSpecified() { + void providesArgumentsUsingLocalQualifiedNameForOverloadedFactoryMethodWhenParameterListIsNotSpecified() { + var arguments = provideArguments("stringStreamProviderWithOrWithoutParameter").toArray(); + + assertThat(arguments).containsExactly(array("foo"), array("bar")); + } + + } + + @Nested + class ErrorCases { + + @Test + void throwsExceptionWhenFullyQualifiedMethodNameSyntaxIsInvalid() { + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments("org.example.wrongSyntax").toArray()); + + assertThat(exception.getMessage()).isEqualTo( + "[org.example.wrongSyntax] is not a valid fully qualified method name: " + + "it must start with a fully qualified class name followed by a '#' and then the method name, " + + "optionally followed by a parameter list enclosed in parentheses."); + } + + @Test + void throwsExceptionWhenClassForExternalFactoryMethodCannotBeLoaded() { + var exception = assertThrows(JUnitException.class, + () -> provideArguments("com.example.NonExistentClass#stringsProvider").toArray()); + + assertThat(exception.getMessage()).isEqualTo("Could not load class [com.example.NonExistentClass]"); + } + + @Test + void throwsExceptionWhenExternalFactoryMethodDoesNotExist() { + String factoryClass = ExternalFactoryMethods.class.getName(); + + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(factoryClass + "#nonExistentMethod").toArray()); + + assertThat(exception.getMessage()).isEqualTo( + "Could not find factory method [nonExistentMethod] in class [%s]", factoryClass); + } + + @Test + void throwsExceptionWhenLocalFactoryMethodDoesNotExist() { + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments("nonExistentMethod").toArray()); + + assertThat(exception.getMessage()).isEqualTo( + "Could not find factory method [nonExistentMethod] in class [%s]", TestCase.class.getName()); + } + + @Test + void throwsExceptionWhenExternalFactoryMethodAcceptingSingleArgumentDoesNotExist() { + String factoryClass = ExternalFactoryMethods.class.getName(); + + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(factoryClass + "#nonExistentMethod(int)").toArray()); + + assertThat(exception.getMessage()).isEqualTo( + "Could not find factory method [nonExistentMethod(int)] in class [%s]", factoryClass); + } + + @Test + void throwsExceptionWhenLocalFactoryMethodAcceptingSingleArgumentDoesNotExist() { + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments("nonExistentMethod(int)").toArray()); + + assertThat(exception.getMessage()).isEqualTo( + "Could not find factory method [nonExistentMethod(int)] in class [%s]", TestCase.class.getName()); + } + + @Test + void throwsExceptionWhenExternalFactoryMethodAcceptingMultipleArgumentsDoesNotExist() { + String factoryClass = ExternalFactoryMethods.class.getName(); + + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(factoryClass + "#nonExistentMethod(int, java.lang.String)").toArray()); + + assertThat(exception.getMessage()).isEqualTo( + "Could not find factory method [nonExistentMethod(int, java.lang.String)] in class [%s]", factoryClass); + } + + @Test + void throwsExceptionWhenLocalFactoryMethodAcceptingMultipleArgumentsDoesNotExist() { var exception = assertThrows(PreconditionViolationException.class, - () -> provideArguments("stringStreamProviderWithOrWithoutParameter").toArray()); + () -> provideArguments("nonExistentMethod(java.lang.String,int)").toArray()); + + assertThat(exception.getMessage()).isEqualTo( + "Could not find factory method [nonExistentMethod(java.lang.String,int)] in class [%s]", + TestCase.class.getName()); + } + + @Test + void throwsExceptionWhenExternalFactoryMethodHasInvalidReturnType() { + String testClass = TestCase.class.getName(); + String factoryClass = ExternalFactoryMethods.class.getName(); + String factoryMethod = factoryClass + "#factoryWithInvalidReturnType"; + + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(TestCase.class, null, false, factoryMethod).toArray()); + + assertThat(exception.getMessage())// + .containsSubsequence("Could not find valid factory method [" + factoryMethod + "] for test class [", + testClass + "]", // + "but found the following invalid candidate: ", + "static java.lang.Object " + factoryClass + ".factoryWithInvalidReturnType()"); + } + + @Test + void throwsExceptionWhenLocalFactoryMethodHasInvalidReturnType() { + String testClass = TestCase.class.getName(); + String factoryClass = testClass; + String factoryMethod = "factoryWithInvalidReturnType"; + + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(factoryMethod).toArray()); assertThat(exception.getMessage())// - .startsWith("3 factory methods named [stringStreamProviderWithOrWithoutParameter] were found in " - + "class [org.junit.jupiter.params.provider.MethodArgumentsProviderTests$TestCase]: ")// - .contains("stringStreamProviderWithOrWithoutParameter()", - "stringStreamProviderWithOrWithoutParameter(java.lang.String)", - "stringStreamProviderWithOrWithoutParameter(java.lang.String,java.lang.String)"); + .containsSubsequence("Could not find valid factory method [" + factoryMethod + "] for test class [", + factoryClass + "]", // + "but found the following invalid candidate: ", // + "static java.lang.Object " + factoryClass + ".factoryWithInvalidReturnType()"); + } + + @Test + void throwsExceptionWhenMultipleDefaultFactoryMethodCandidatesExist() { + var testClass = MultipleDefaultFactoriesTestCase.class; + var methodName = "test"; + var testMethod = findMethod(testClass, methodName, String.class).get(); + + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(testClass, testMethod, false, "").toArray()); + + assertThat(exception.getMessage()).contains(// + "2 factory methods named [test] were found in class [", testClass.getName() + "]: ", // + "$MultipleDefaultFactoriesTestCase.test()", // + "$MultipleDefaultFactoriesTestCase.test(int)"// + ); + } + + @Test + void throwsExceptionWhenMultipleInvalidDefaultFactoryMethodCandidatesExist() { + var testClass = MultipleInvalidDefaultFactoriesTestCase.class; + var methodName = "test"; + var testMethod = findMethod(testClass, methodName, String.class).get(); + + var exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(testClass, testMethod, false, "").toArray()); + + assertThat(exception.getMessage()).contains(// + "Could not find valid factory method [test] in class [", testClass.getName() + "]", // + "but found the following invalid candidates: ", // + "$MultipleInvalidDefaultFactoriesTestCase.test()", // + "$MultipleInvalidDefaultFactoriesTestCase.test(int)"// + ); } } @@ -585,8 +684,13 @@ private Stream provideArguments(Class testClass, Method testMethod, if (testMethod == null) { try { + class DummyClass { + @SuppressWarnings("unused") + public void dummyMethod() { + }; + } // ensure we have a non-null method, even if it's not a real test method. - testMethod = getClass().getMethod("toString"); + testMethod = DummyClass.class.getMethod("dummyMethod"); } catch (Exception ex) { throw new RuntimeException(ex); @@ -618,13 +722,47 @@ private Stream provideArguments(Class testClass, Method testMethod, static class DefaultFactoryMethodNameTestCase { - static final String TEST_METHOD = "testDefaultFactoryMethodName"; + // Test + void testDefaultFactoryMethodName(String param) { + } + // Factory static Stream testDefaultFactoryMethodName() { return Stream.of("foo", "bar"); } + } + + static class MultipleDefaultFactoriesTestCase { + + // Test + void test(String param) { + } - void testDefaultFactoryMethodName(String param) { + // Factory + static Stream test() { + return Stream.of(); + } + + // Another Factory + static Stream test(int num) { + return Stream.of(); + } + } + + static class MultipleInvalidDefaultFactoriesTestCase { + + // Test + void test(String param) { + } + + // NOT a Factory + static String test() { + return null; + } + + // Also NOT a Factory + static Object test(int num) { + return null; } } @@ -635,7 +773,7 @@ void test() { // --- Invalid --------------------------------------------------------- - static Object providerWithIllegalReturnType() { + static Object factoryWithInvalidReturnType() { return -1; } @@ -671,6 +809,10 @@ static Stream stringStreamProviderWithOrWithoutParameter(String paramete return stringStreamProviderWithParameter(parameter1 + parameter2); } + // Overloaded method, but not a valid return type for a factory method + static void stringStreamProviderWithOrWithoutParameter(String parameter1, int parameter2) { + } + // @ParameterizedTest // @MethodSource // use default, inferred factory method void overloadedStringStreamProvider(Object parameter) { @@ -798,6 +940,10 @@ Stream nonStaticStringStreamProvider() { static class ExternalFactoryMethods { + static Object factoryWithInvalidReturnType() { + return -1; + } + static Stream stringsProvider() { return Stream.of("string1", "string2"); } From e575ea3e9c7f3ce95c794accbd81904a1ce92599 Mon Sep 17 00:00:00 2001 From: Ale Mendoza Date: Fri, 21 Apr 2023 13:16:27 -0600 Subject: [PATCH 20/25] Do not parse {displayName} for @ParameterizedTest using MessageFormat Prior to this commit, if a @ParameterizedTest used the {displayName} placeholder to generate a display name and the value of the displayName contained an apostrophe (') or something resembling a MessageFormat element (such as {data}), JUnit threw an exception due to failure to parse the display name. This is applicable to method names in Kotlin-based tests or custom display names in general. To fix this bug, instead of replacing the DISPLAY_NAME_PLACEHOLDER before the MessageFormat is evaluated, the DISPLAY_NAME_PLACEHOLDER is now replaced with another temporary placeholder, which is then replaced after the MessageFormat has been evaluated. Closes #3235 Closes #3264 --- .../release-notes-5.10.0-M1.adoc | 102 ++++++++++++++++++ .../ParameterizedTestNameFormatter.java | 6 +- .../ParameterizedTestNameFormatterTests.java | 18 ++++ ...erizedTestNameFormatterIntegrationTests.kt | 62 +++++++++++ 4 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc create mode 100644 junit-jupiter-params/src/test/kotlin/ParameterizedTestNameFormatterIntegrationTests.kt diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc new file mode 100644 index 000000000000..1308b0e792a0 --- /dev/null +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc @@ -0,0 +1,102 @@ +[[release-notes-5.10.0-M1]] +== 5.10.0-M1 + +*Date of Release:* ❓ + +*Scope:* ❓ + +For a complete list of all _closed_ issues and pull requests for this release, consult the +link:{junit5-repo}+/milestone/65?closed=1+[5.10.0-M1] milestone page in the JUnit +repository on GitHub. + + +[[release-notes-5.10.0-M1-junit-platform]] +=== JUnit Platform + +==== Bug Fixes + +* ❓ + +==== Deprecations and Breaking Changes + +* Building native images with GraalVM now requires configuring the build arg + `--initialize-at-build-time=org.junit.platform.launcher.core.LauncherConfig`. + +==== New Features and Improvements + +* Promote various "experimental" APIs that have matured to "stable" including + `ModuleSelector`, `EngineDiscoveryListener`, `EngineDiscoveryRequestResolver`, + `LauncherSession`, `LauncherSessionListener`, parallel execution support classes, + `@Suite` and related annotations, and others. +* All utility methods in `ReflectionSupport` that return a `List` now have counterparts + which return a `Stream`. +* For consistency with JUnit Jupiter lifecycle callbacks, listener method pairs for + started/finished and opened/closed events are now invoked using "wrapping" semantics. + This means that finished/closed event methods are invoked in reverse order compared to + the corresponding started/opened event methods when multiple listeners are registered. + This affects the following listener interfaces: + `TestExecutionListener`, `EngineExecutionListener`, `LauncherDiscoveryListener`, and + `LauncherSessionListener`. +* New `LauncherInterceptor` SPI for intercepting the creation of instances of `Launcher` + and `LauncherSessionlistener` as well as invocations of the `discover` and `execute` + methods of the former. Please refer to the + <<../user-guide/index.adoc#launcher-api-launcher-interceptors-custom, User Guide>> for + details. +* Support for limiting the `max-pool-size-factor` for parallel execution via a configuration parameter. +* The new `testfeed` details mode for `ConsoleLauncher` prints test execution events as + they occur in a concise format. + + +[[release-notes-5.10.0-M1-junit-jupiter]] +=== JUnit Jupiter + +==== Bug Fixes + +* The `{displayName}` placeholder of `@ParameterizedTest` is no longer parsed during the + evaluation of the `MessageFormat`, now `@DisplayName` and Kotlin method names can contain + single apostrophes and `MessageFormat` elements, such as `{data}`. + +==== Deprecations and Breaking Changes + +* The `dynamic` parallel execution strategy now allows the thread pool to be saturated by +default. + +==== New Features and Improvements + +* Promote various "experimental" APIs that have matured to "stable" including + `MethodOrderer`, `ClassOrderer`, `InvocationInterceptor`, + `LifecycleMethodExecutionExceptionHandler`, `@TempDir`, parallel execution annotations, + and others. +* `@RepeatedTest` can now be configured with a failure threshold which signifies the + number of failures after which remaining repetitions will be automatically skipped. See + the <<../user-guide/index.adoc#writing-tests-repeated-tests, User Guide>> for details. +* New `ArgumentsAccessor.getInvocationIndex()` method that supplies the index of a + `@ParameterizedTest` invocation. +* `@EmptySource` now supports additional types, including `Collection` and `Map` subtypes + with a public no-arg constructor. +* `DisplayNameGenerator` methods are now allowed to return `null`, in order to signal to + fall back to the default display name generator. +* New `AnnotationBasedArgumentsProvider` convenience base class which implements both + `ArgumentsProvider` and `AnnotationConsumer`. +* New `AnnotationBasedArgumentConverter` convenience base class which implements both + `ArgumentConverter` and `AnnotationConsumer`. +* New `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` configuration + parameter to set the maximum pool size factor. +* New `junit.jupiter.execution.parallel.config.dynamic.saturate` configuration + parameter to disable pool saturation. + + +[[release-notes-5.10.0-M1-junit-vintage]] +=== JUnit Vintage + +==== Bug Fixes + +* ❓ + +==== Deprecations and Breaking Changes + +* ❓ + +==== New Features and Improvements + +* ❓ diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java index 4d8899d89639..800f146b70b0 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java @@ -31,6 +31,7 @@ class ParameterizedTestNameFormatter { private static final char ELLIPSIS = '\u2026'; + private static final String DISPLAY_NAME_TEMPORARY_PLACEHOLDER = "__DISPLAY_NAME__"; private final String pattern; private final String displayName; @@ -61,7 +62,8 @@ private String formatSafely(int invocationIndex, Object[] arguments) { String pattern = prepareMessageFormatPattern(invocationIndex, namedArguments); MessageFormat format = new MessageFormat(pattern); Object[] humanReadableArguments = makeReadable(format, namedArguments); - return format.format(humanReadableArguments); + String formatted = format.format(humanReadableArguments); + return formatted.replace(DISPLAY_NAME_TEMPORARY_PLACEHOLDER, this.displayName); } private Object[] extractNamedArguments(Object[] arguments) { @@ -72,7 +74,7 @@ private Object[] extractNamedArguments(Object[] arguments) { private String prepareMessageFormatPattern(int invocationIndex, Object[] arguments) { String result = pattern// - .replace(DISPLAY_NAME_PLACEHOLDER, this.displayName)// + .replace(DISPLAY_NAME_PLACEHOLDER, DISPLAY_NAME_TEMPORARY_PLACEHOLDER)// .replace(INDEX_PLACEHOLDER, String.valueOf(invocationIndex)); if (result.contains(ARGUMENTS_WITH_NAMES_PLACEHOLDER)) { diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java index e83f88fc0f62..ad63dbdede43 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java @@ -60,6 +60,24 @@ void formatsDisplayName() { assertEquals("enigma", formatter.format(2)); } + @Test + void formatsDisplayNameWithApostrophe() { + String displayName = "display'Zero"; + var formatter = formatter(DISPLAY_NAME_PLACEHOLDER, "display'Zero"); + + assertEquals(displayName, formatter.format(1)); + assertEquals(displayName, formatter.format(2)); + } + + @Test + void formatsDisplayNameContainingFormatElements() { + String displayName = "{enigma} {0} '{1}'"; + var formatter = formatter(DISPLAY_NAME_PLACEHOLDER, displayName); + + assertEquals(displayName, formatter.format(1)); + assertEquals(displayName, formatter.format(2)); + } + @Test void formatsInvocationIndex() { var formatter = formatter(INDEX_PLACEHOLDER, "enigma"); diff --git a/junit-jupiter-params/src/test/kotlin/ParameterizedTestNameFormatterIntegrationTests.kt b/junit-jupiter-params/src/test/kotlin/ParameterizedTestNameFormatterIntegrationTests.kt new file mode 100644 index 000000000000..afcfb4bde7a2 --- /dev/null +++ b/junit-jupiter-params/src/test/kotlin/ParameterizedTestNameFormatterIntegrationTests.kt @@ -0,0 +1,62 @@ +/* + * 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 + */ +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.TestInfo +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class ParameterizedTestNameFormatterIntegrationTests { + + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest + fun `implicit'Name`(param: String, info: TestInfo) { + if (param.equals("foo")) { + assertEquals("[1] foo", info.displayName) + } else { + assertEquals("[2] bar", info.displayName) + } + } + + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest(name = "{0}") + fun `zero'Only`(param: String, info: TestInfo) { + if (param.equals("foo")) { + assertEquals("foo", info.displayName) + } else { + assertEquals("bar", info.displayName) + } + } + + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest(name = "{displayName}") + fun `displayName'Only`(param: String, info: TestInfo) { + assertEquals("displayName'Only(String, TestInfo)", info.displayName) + } + + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest(name = "{displayName} - {0}") + fun `displayName'Zero`(param: String, info: TestInfo) { + if (param.equals("foo")) { + assertEquals("displayName'Zero(String, TestInfo) - foo", info.displayName) + } else { + assertEquals("displayName'Zero(String, TestInfo) - bar", info.displayName) + } + } + + @ValueSource(strings = ["foo", "bar"]) + @ParameterizedTest(name = "{0} - {displayName}") + fun `zero'DisplayName`(param: String, info: TestInfo) { + if (param.equals("foo")) { + assertEquals("foo - zero'DisplayName(String, TestInfo)", info.displayName) + } else { + assertEquals("bar - zero'DisplayName(String, TestInfo)", info.displayName) + } + } +} From 6c02c060d3a2c89f481475b8142aa543e3816772 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 24 Apr 2023 13:56:33 +0200 Subject: [PATCH 21/25] Polish contribution See #3264 --- .../release-notes-5.10.0-M1.adoc | 9 ++++++--- .../ParameterizedTestNameFormatter.java | 6 +++--- .../ParameterizedTestNameFormatterTests.java | 2 +- ...erizedTestNameFormatterIntegrationTests.kt | 20 +++++++++---------- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc index 1308b0e792a0..809bdfc65fa5 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc @@ -52,9 +52,12 @@ repository on GitHub. ==== Bug Fixes -* The `{displayName}` placeholder of `@ParameterizedTest` is no longer parsed during the - evaluation of the `MessageFormat`, now `@DisplayName` and Kotlin method names can contain - single apostrophes and `MessageFormat` elements, such as `{data}`. +* The `{displayName}` placeholder for `@ParameterizedTest` invocation names is no longer + parsed using `java.text.MessageFormat`. Consequently, any text in the display name of + the `@ParameterizedTest` method will be included unmodified in the invocation display + name. For example, Kotlin method names and custom display names configured via + `@DisplayName` can now contain apostrophes (`'`) as well as text resembling + `MessageFormat` elements such as `{0}` or `{data}`. ==== Deprecations and Breaking Changes diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java index 800f146b70b0..a505bd81f91e 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/ParameterizedTestNameFormatter.java @@ -31,7 +31,7 @@ class ParameterizedTestNameFormatter { private static final char ELLIPSIS = '\u2026'; - private static final String DISPLAY_NAME_TEMPORARY_PLACEHOLDER = "__DISPLAY_NAME__"; + private static final String TEMPORARY_DISPLAY_NAME_PLACEHOLDER = "~~~JUNIT_DISPLAY_NAME~~~"; private final String pattern; private final String displayName; @@ -63,7 +63,7 @@ private String formatSafely(int invocationIndex, Object[] arguments) { MessageFormat format = new MessageFormat(pattern); Object[] humanReadableArguments = makeReadable(format, namedArguments); String formatted = format.format(humanReadableArguments); - return formatted.replace(DISPLAY_NAME_TEMPORARY_PLACEHOLDER, this.displayName); + return formatted.replace(TEMPORARY_DISPLAY_NAME_PLACEHOLDER, this.displayName); } private Object[] extractNamedArguments(Object[] arguments) { @@ -74,7 +74,7 @@ private Object[] extractNamedArguments(Object[] arguments) { private String prepareMessageFormatPattern(int invocationIndex, Object[] arguments) { String result = pattern// - .replace(DISPLAY_NAME_PLACEHOLDER, DISPLAY_NAME_TEMPORARY_PLACEHOLDER)// + .replace(DISPLAY_NAME_PLACEHOLDER, TEMPORARY_DISPLAY_NAME_PLACEHOLDER)// .replace(INDEX_PLACEHOLDER, String.valueOf(invocationIndex)); if (result.contains(ARGUMENTS_WITH_NAMES_PLACEHOLDER)) { diff --git a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java index ad63dbdede43..1cbabc827991 100644 --- a/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java +++ b/junit-jupiter-params/src/test/java/org/junit/jupiter/params/ParameterizedTestNameFormatterTests.java @@ -61,7 +61,7 @@ void formatsDisplayName() { } @Test - void formatsDisplayNameWithApostrophe() { + void formatsDisplayNameContainingApostrophe() { String displayName = "display'Zero"; var formatter = formatter(DISPLAY_NAME_PLACEHOLDER, "display'Zero"); diff --git a/junit-jupiter-params/src/test/kotlin/ParameterizedTestNameFormatterIntegrationTests.kt b/junit-jupiter-params/src/test/kotlin/ParameterizedTestNameFormatterIntegrationTests.kt index afcfb4bde7a2..829f98aefabc 100644 --- a/junit-jupiter-params/src/test/kotlin/ParameterizedTestNameFormatterIntegrationTests.kt +++ b/junit-jupiter-params/src/test/kotlin/ParameterizedTestNameFormatterIntegrationTests.kt @@ -16,7 +16,7 @@ class ParameterizedTestNameFormatterIntegrationTests { @ValueSource(strings = ["foo", "bar"]) @ParameterizedTest - fun `implicit'Name`(param: String, info: TestInfo) { + fun defaultDisplayName(param: String, info: TestInfo) { if (param.equals("foo")) { assertEquals("[1] foo", info.displayName) } else { @@ -26,7 +26,7 @@ class ParameterizedTestNameFormatterIntegrationTests { @ValueSource(strings = ["foo", "bar"]) @ParameterizedTest(name = "{0}") - fun `zero'Only`(param: String, info: TestInfo) { + fun `1st argument`(param: String, info: TestInfo) { if (param.equals("foo")) { assertEquals("foo", info.displayName) } else { @@ -36,27 +36,27 @@ class ParameterizedTestNameFormatterIntegrationTests { @ValueSource(strings = ["foo", "bar"]) @ParameterizedTest(name = "{displayName}") - fun `displayName'Only`(param: String, info: TestInfo) { - assertEquals("displayName'Only(String, TestInfo)", info.displayName) + fun `it's an {enigma} '{0}'`(@Suppress("UNUSED_PARAMETER") param: String, info: TestInfo) { + assertEquals("it's an {enigma} '{0}'(String, TestInfo)", info.displayName) } @ValueSource(strings = ["foo", "bar"]) @ParameterizedTest(name = "{displayName} - {0}") - fun `displayName'Zero`(param: String, info: TestInfo) { + fun `displayName and 1st 'argument'`(param: String, info: TestInfo) { if (param.equals("foo")) { - assertEquals("displayName'Zero(String, TestInfo) - foo", info.displayName) + assertEquals("displayName and 1st 'argument'(String, TestInfo) - foo", info.displayName) } else { - assertEquals("displayName'Zero(String, TestInfo) - bar", info.displayName) + assertEquals("displayName and 1st 'argument'(String, TestInfo) - bar", info.displayName) } } @ValueSource(strings = ["foo", "bar"]) @ParameterizedTest(name = "{0} - {displayName}") - fun `zero'DisplayName`(param: String, info: TestInfo) { + fun `1st 'argument' and displayName`(param: String, info: TestInfo) { if (param.equals("foo")) { - assertEquals("foo - zero'DisplayName(String, TestInfo)", info.displayName) + assertEquals("foo - 1st 'argument' and displayName(String, TestInfo)", info.displayName) } else { - assertEquals("bar - zero'DisplayName(String, TestInfo)", info.displayName) + assertEquals("bar - 1st 'argument' and displayName(String, TestInfo)", info.displayName) } } } From 468958d647d8f5c3cad075ee79ee91033356ad2b Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 24 Apr 2023 14:13:30 +0200 Subject: [PATCH 22/25] Move release note for #3235/#3264 to 5.9.3 --- .../release-notes-5.10.0-M1.adoc | 105 ------------------ .../release-notes/release-notes-5.9.3.adoc | 6 + 2 files changed, 6 insertions(+), 105 deletions(-) delete mode 100644 documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc deleted file mode 100644 index 809bdfc65fa5..000000000000 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-M1.adoc +++ /dev/null @@ -1,105 +0,0 @@ -[[release-notes-5.10.0-M1]] -== 5.10.0-M1 - -*Date of Release:* ❓ - -*Scope:* ❓ - -For a complete list of all _closed_ issues and pull requests for this release, consult the -link:{junit5-repo}+/milestone/65?closed=1+[5.10.0-M1] milestone page in the JUnit -repository on GitHub. - - -[[release-notes-5.10.0-M1-junit-platform]] -=== JUnit Platform - -==== Bug Fixes - -* ❓ - -==== Deprecations and Breaking Changes - -* Building native images with GraalVM now requires configuring the build arg - `--initialize-at-build-time=org.junit.platform.launcher.core.LauncherConfig`. - -==== New Features and Improvements - -* Promote various "experimental" APIs that have matured to "stable" including - `ModuleSelector`, `EngineDiscoveryListener`, `EngineDiscoveryRequestResolver`, - `LauncherSession`, `LauncherSessionListener`, parallel execution support classes, - `@Suite` and related annotations, and others. -* All utility methods in `ReflectionSupport` that return a `List` now have counterparts - which return a `Stream`. -* For consistency with JUnit Jupiter lifecycle callbacks, listener method pairs for - started/finished and opened/closed events are now invoked using "wrapping" semantics. - This means that finished/closed event methods are invoked in reverse order compared to - the corresponding started/opened event methods when multiple listeners are registered. - This affects the following listener interfaces: - `TestExecutionListener`, `EngineExecutionListener`, `LauncherDiscoveryListener`, and - `LauncherSessionListener`. -* New `LauncherInterceptor` SPI for intercepting the creation of instances of `Launcher` - and `LauncherSessionlistener` as well as invocations of the `discover` and `execute` - methods of the former. Please refer to the - <<../user-guide/index.adoc#launcher-api-launcher-interceptors-custom, User Guide>> for - details. -* Support for limiting the `max-pool-size-factor` for parallel execution via a configuration parameter. -* The new `testfeed` details mode for `ConsoleLauncher` prints test execution events as - they occur in a concise format. - - -[[release-notes-5.10.0-M1-junit-jupiter]] -=== JUnit Jupiter - -==== Bug Fixes - -* The `{displayName}` placeholder for `@ParameterizedTest` invocation names is no longer - parsed using `java.text.MessageFormat`. Consequently, any text in the display name of - the `@ParameterizedTest` method will be included unmodified in the invocation display - name. For example, Kotlin method names and custom display names configured via - `@DisplayName` can now contain apostrophes (`'`) as well as text resembling - `MessageFormat` elements such as `{0}` or `{data}`. - -==== Deprecations and Breaking Changes - -* The `dynamic` parallel execution strategy now allows the thread pool to be saturated by -default. - -==== New Features and Improvements - -* Promote various "experimental" APIs that have matured to "stable" including - `MethodOrderer`, `ClassOrderer`, `InvocationInterceptor`, - `LifecycleMethodExecutionExceptionHandler`, `@TempDir`, parallel execution annotations, - and others. -* `@RepeatedTest` can now be configured with a failure threshold which signifies the - number of failures after which remaining repetitions will be automatically skipped. See - the <<../user-guide/index.adoc#writing-tests-repeated-tests, User Guide>> for details. -* New `ArgumentsAccessor.getInvocationIndex()` method that supplies the index of a - `@ParameterizedTest` invocation. -* `@EmptySource` now supports additional types, including `Collection` and `Map` subtypes - with a public no-arg constructor. -* `DisplayNameGenerator` methods are now allowed to return `null`, in order to signal to - fall back to the default display name generator. -* New `AnnotationBasedArgumentsProvider` convenience base class which implements both - `ArgumentsProvider` and `AnnotationConsumer`. -* New `AnnotationBasedArgumentConverter` convenience base class which implements both - `ArgumentConverter` and `AnnotationConsumer`. -* New `junit.jupiter.execution.parallel.config.dynamic.max-pool-size-factor` configuration - parameter to set the maximum pool size factor. -* New `junit.jupiter.execution.parallel.config.dynamic.saturate` configuration - parameter to disable pool saturation. - - -[[release-notes-5.10.0-M1-junit-vintage]] -=== JUnit Vintage - -==== Bug Fixes - -* ❓ - -==== Deprecations and Breaking Changes - -* ❓ - -==== New Features and Improvements - -* ❓ diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc index cb4b0f1ec7a2..a084dceab9d3 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc @@ -43,6 +43,12 @@ JUnit repository on GitHub. * The search algorithm used to find `@MethodSource` factory methods now applies consistent semantics for _local_ qualified method names and fully-qualified method names for overloaded factory methods. +* The `{displayName}` placeholder for `@ParameterizedTest` invocation names is no longer + parsed using `java.text.MessageFormat`. Consequently, any text in the display name of + the `@ParameterizedTest` method will be included unmodified in the invocation display + name. For example, Kotlin method names and custom display names configured via + `@DisplayName` can now contain apostrophes (`'`) as well as text resembling + `MessageFormat` elements such as `{0}` or `{data}`. * Exceptions thrown for files that cannot be deleted when cleaning up a temporary directory created via `@TempDir` now include the root cause. * Lifecycle methods are allowed to be declared as `private` again for backwards From 8116548985b39b8e0b24a780d6f26ed560b7b94a Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 24 Apr 2023 14:25:14 +0200 Subject: [PATCH 23/25] Prepare release notes for 5.9.3 --- .../release-notes/release-notes-5.9.3.adoc | 32 +++---------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc index a084dceab9d3..0f0ecd97d930 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc @@ -1,9 +1,9 @@ [[release-notes-5.9.3]] == 5.9.3 -*Date of Release:* ❓ +*Date of Release:* April ❓, 2023 -*Scope:* ❓ +*Scope:* Bug fixes and enhancements since 5.9.2 For a complete list of all _closed_ issues and pull requests for this release, consult the link:{junit5-repo}+/milestone/67?closed=1+[5.9.3] milestone page in the @@ -13,17 +13,7 @@ JUnit repository on GitHub. [[release-notes-5.9.3-junit-platform]] === JUnit Platform -==== Bug Fixes - -* ❓ - -==== Deprecations and Breaking Changes - -* ❓ - -==== New Features and Improvements - -* ❓ +No changes. [[release-notes-5.9.3-junit-jupiter]] @@ -55,10 +45,6 @@ JUnit repository on GitHub. compatibility; however, using `private` visibility for lifecycle methods is strongly discouraged and will be disallowed in a future release. -==== Deprecations and Breaking Changes - -* ❓ - ==== New Features and Improvements * The search algorithm used to find `@MethodSource` factory methods now falls back to @@ -70,14 +56,4 @@ JUnit repository on GitHub. [[release-notes-5.9.3-junit-vintage]] === JUnit Vintage -==== Bug Fixes - -* ❓ - -==== Deprecations and Breaking Changes - -* ❓ - -==== New Features and Improvements - -* ❓ +No changes. From 2afe30a0765c55a371828b216059cb62aa673dda Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Wed, 26 Apr 2023 08:23:40 +0200 Subject: [PATCH 24/25] Finalize 5.9.3 release notes --- .../asciidoc/release-notes/release-notes-5.9.3.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc index 0f0ecd97d930..09dc2a8e9f45 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.9.3.adoc @@ -1,7 +1,7 @@ [[release-notes-5.9.3]] == 5.9.3 -*Date of Release:* April ❓, 2023 +*Date of Release:* April 26, 2023 *Scope:* Bug fixes and enhancements since 5.9.2 @@ -33,12 +33,12 @@ No changes. * The search algorithm used to find `@MethodSource` factory methods now applies consistent semantics for _local_ qualified method names and fully-qualified method names for overloaded factory methods. -* The `{displayName}` placeholder for `@ParameterizedTest` invocation names is no longer - parsed using `java.text.MessageFormat`. Consequently, any text in the display name of +* The `+{displayName}+` placeholder for `@ParameterizedTest` invocation names is no longer + parsed using `java.text.MessageFormat`.Consequently, any text in the display name of the `@ParameterizedTest` method will be included unmodified in the invocation display - name. For example, Kotlin method names and custom display names configured via + name.For example, Kotlin method names and custom display names configured via `@DisplayName` can now contain apostrophes (`'`) as well as text resembling - `MessageFormat` elements such as `{0}` or `{data}`. + `MessageFormat` elements such as `+{0}+` or `+{data}+`. * Exceptions thrown for files that cannot be deleted when cleaning up a temporary directory created via `@TempDir` now include the root cause. * Lifecycle methods are allowed to be declared as `private` again for backwards From bd7d03f517dfca3730fbd123c5fd4d4b70930129 Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Wed, 26 Apr 2023 08:27:05 +0200 Subject: [PATCH 25/25] Release 5.9.3 --- README.md | 2 +- gradle.properties | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7b4bb98a40c3..59318bd5bb92 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This repository is the home of the next generation of JUnit, _JUnit 5_. ## Latest Releases -- General Availability (GA): [JUnit 5.9.2](https://github.com/junit-team/junit5/releases/tag/r5.9.2) (January 10, 2023) +- General Availability (GA): [JUnit 5.9.3](https://github.com/junit-team/junit5/releases/tag/r5.9.3) (April 26, 2023) - Preview (Milestone/Release Candidate): n/a ## Documentation diff --git a/gradle.properties b/gradle.properties index 2fd0518f4bd8..646efedee055 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,13 +1,13 @@ group = org.junit -version = 5.9.3-SNAPSHOT +version = 5.9.3 jupiterGroup = org.junit.jupiter platformGroup = org.junit.platform -platformVersion = 1.9.3-SNAPSHOT +platformVersion = 1.9.3 vintageGroup = org.junit.vintage -vintageVersion = 5.9.3-SNAPSHOT +vintageVersion = 5.9.3 defaultBuiltBy = JUnit Team