From 56557dcfc24e4f9b101e39f239c36d9e5ceb5b32 Mon Sep 17 00:00:00 2001 From: yhkuo41 Date: Tue, 24 Dec 2024 17:32:33 +0800 Subject: [PATCH 1/3] Introduce from and to attributes on @EnumSource (#4185) Resolves #4185. --- .../release-notes-5.12.0-M1.adoc | 2 + .../asciidoc/user-guide/writing-tests.adoc | 26 ++++- .../java/example/ParameterizedTestDemo.java | 17 +++ .../provider/EnumArgumentsProvider.java | 8 +- .../jupiter/params/provider/EnumSource.java | 42 ++++++- .../provider/EnumArgumentsProviderTests.java | 103 +++++++++++++++--- 6 files changed, 175 insertions(+), 23 deletions(-) diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc index 3c29620bee9a..1067b32a0ba1 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.12.0-M1.adoc @@ -137,6 +137,8 @@ JUnit repository on GitHub. thread dump to `System.out` prior to interrupting a test thread due to a timeout. * `TestReporter` now allows publishing files for a test method or test class which can be used to include them in test reports, such as the Open Test Reporting format. +* New `from` and `to` attributes added to `@EnumSource` to support range selection of + enum constants. [[release-notes-5.12.0-M1-junit-vintage]] diff --git a/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc b/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc index 25a442d6c295..286727143a94 100644 --- a/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc +++ b/documentation/src/docs/asciidoc/user-guide/writing-tests.adoc @@ -1560,14 +1560,28 @@ include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_example_au ---- The annotation provides an optional `names` attribute that lets you specify which -constants shall be used, like in the following example. If omitted, all constants will be -used. +constants shall be used, like in the following example. [source,java,indent=0] ---- include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_include_example] ---- +In addition to `names`, you can use the `from` and `to` attributes to specify a range of +constants. The range starts from the constant specified in the `from` attribute and +includes all subsequent constants up to and including the one specified in the `to` +attribute, based on the natural order of the enum constants. + +If `from` and `to` attributes are omitted, they default to the first and last constants +in the enum type, respectively. If all `names`, `from`, and `to` attributes are omitted, +all constants will be used. The following example demonstrates how to specify a range of +constants. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_example] +---- + The `@EnumSource` annotation also provides an optional `mode` attribute that enables fine-grained control over which constants are passed to the test method. For example, you can exclude names from the enum constant pool or specify regular expressions as in the @@ -1583,6 +1597,14 @@ include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_exclude_ex include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_regex_example] ---- +You can also combine `mode` with the `from`, `to` and `names` attributes to define a +range of constants while excluding specific values from that range as shown below. + +[source,java,indent=0] +---- +include::{testDir}/example/ParameterizedTestDemo.java[tags=EnumSource_range_exclude_example] +---- + [[writing-tests-parameterized-tests-sources-MethodSource]] ===== @MethodSource diff --git a/documentation/src/test/java/example/ParameterizedTestDemo.java b/documentation/src/test/java/example/ParameterizedTestDemo.java index 894b7617761d..4a200726ebcd 100644 --- a/documentation/src/test/java/example/ParameterizedTestDemo.java +++ b/documentation/src/test/java/example/ParameterizedTestDemo.java @@ -148,6 +148,14 @@ void testWithEnumSourceInclude(ChronoUnit unit) { } // end::EnumSource_include_example[] + // tag::EnumSource_range_example[] + @ParameterizedTest + @EnumSource(from = "HOURS", to = "DAYS") + void testWithEnumSourceRange(ChronoUnit unit) { + assertTrue(EnumSet.of(ChronoUnit.HOURS, ChronoUnit.HALF_DAYS, ChronoUnit.DAYS).contains(unit)); + } + // end::EnumSource_range_example[] + // tag::EnumSource_exclude_example[] @ParameterizedTest @EnumSource(mode = EXCLUDE, names = { "ERAS", "FOREVER" }) @@ -164,6 +172,15 @@ void testWithEnumSourceRegex(ChronoUnit unit) { } // end::EnumSource_regex_example[] + // tag::EnumSource_range_exclude_example[] + @ParameterizedTest + @EnumSource(mode = EXCLUDE, from = "HOURS", to = "DAYS", names = { "HALF_DAYS" }) + void testWithEnumSourceRangeExclude(ChronoUnit unit) { + assertTrue(EnumSet.of(ChronoUnit.HOURS, ChronoUnit.DAYS).contains(unit)); + assertFalse(EnumSet.of(ChronoUnit.HALF_DAYS).contains(unit)); + } + // end::EnumSource_range_exclude_example[] + // tag::simple_MethodSource_example[] @ParameterizedTest @MethodSource("stringProvider") diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java index 0a525289e566..a68b43d5f371 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java @@ -43,7 +43,13 @@ protected Stream provideArguments(ExtensionContext context, private > Set getEnumConstants(ExtensionContext context, EnumSource enumSource) { Class enumClass = determineEnumClass(context, enumSource); - return EnumSet.allOf(enumClass); + E[] constants = enumClass.getEnumConstants(); + if (constants.length == 0) { + return EnumSet.noneOf(enumClass); + } + E from = enumSource.from().isEmpty() ? constants[0] : Enum.valueOf(enumClass, enumSource.from()); + E to = enumSource.to().isEmpty() ? constants[constants.length - 1] : Enum.valueOf(enumClass, enumSource.to()); + return EnumSet.range(from, to); } @SuppressWarnings({ "unchecked", "rawtypes" }) diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java index 3bf7e9b88e5e..673066b163b2 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java @@ -40,8 +40,8 @@ * attribute. Otherwise, the declared type of the first parameter of the * {@code @ParameterizedTest} method is used. * - *

The set of enum constants can be restricted via the {@link #names} and - * {@link #mode} attributes. + *

The set of enum constants can be restricted via the {@link #names}, + * {@link #from}, {@link #to} and {@link #mode} attributes. * * @since 5.0 * @see org.junit.jupiter.params.provider.ArgumentsSource @@ -63,6 +63,8 @@ * first parameter of the {@code @ParameterizedTest} method is used. * * @see #names + * @see #from + * @see #to * @see #mode */ Class> value() default NullEnum.class; @@ -71,16 +73,48 @@ * The names of enum constants to provide, or regular expressions to select * the names of enum constants to provide. * - *

If no names or regular expressions are specified, all enum constants - * declared in the specified {@linkplain #value enum type} will be provided. + *

If no names or regular expressions are specified, and neither {@link #from} + * nor {@link #to} are specified, all enum constants declared in the specified + * {@linkplain #value enum type} will be provided. + * + *

If {@link #from} or {@link #to} are specified, the elements in names must + * fall within the range defined by {@link #from} and {@link #to}. * *

The {@link #mode} determines how the names are interpreted. * * @see #value + * @see #from + * @see #to * @see #mode */ String[] names() default {}; + /** + * The starting enum constant of the range to be included. + * + *

Defaults to an empty string, where the range starts from the first enum + * constant of the specified {@linkplain #value enum type}. + * + * @see #value + * @see #names + * @see #to + * @see #mode + */ + String from() default ""; + + /** + * The ending enum constant of the range to be included. + * + *

Defaults to an empty string, where the range ends at the last enum + * constant of the specified {@linkplain #value enum type}. + * + * @see #value + * @see #names + * @see #from + * @see #mode + */ + String to() default ""; + /** * The enum constant selection mode. * diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java index 6a5312085776..a3c405dcf23b 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java @@ -12,8 +12,10 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithTwoConstants.BAR; -import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithTwoConstants.FOO; +import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithFourConstants.BAR; +import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithFourConstants.BAZ; +import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithFourConstants.FOO; +import static org.junit.jupiter.params.provider.EnumArgumentsProviderTests.EnumWithFourConstants.QUX; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -34,21 +36,22 @@ class EnumArgumentsProviderTests { @Test void providesAllEnumConstants() { - var arguments = provideArguments(EnumWithTwoConstants.class); + var arguments = provideArguments(EnumWithFourConstants.class); - assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }); + assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }, new Object[] { BAZ }, + new Object[] { QUX }); } @Test void provideSingleEnumConstant() { - var arguments = provideArguments(EnumWithTwoConstants.class, "FOO"); + var arguments = provideArguments(EnumWithFourConstants.class, "FOO"); assertThat(arguments).containsExactly(new Object[] { FOO }); } @Test void provideAllEnumConstantsWithNamingAll() { - var arguments = provideArguments(EnumWithTwoConstants.class, "FOO", "BAR"); + var arguments = provideArguments(EnumWithFourConstants.class, "FOO", "BAR"); assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }); } @@ -56,32 +59,33 @@ void provideAllEnumConstantsWithNamingAll() { @Test void duplicateConstantNameIsDetected() { Exception exception = assertThrows(PreconditionViolationException.class, - () -> provideArguments(EnumWithTwoConstants.class, "FOO", "BAR", "FOO").findAny()); + () -> provideArguments(EnumWithFourConstants.class, "FOO", "BAR", "FOO").findAny()); assertThat(exception).hasMessageContaining("Duplicate enum constant name(s) found"); } @Test void invalidConstantNameIsDetected() { Exception exception = assertThrows(PreconditionViolationException.class, - () -> provideArguments(EnumWithTwoConstants.class, "FO0", "B4R").findAny()); + () -> provideArguments(EnumWithFourConstants.class, "FO0", "B4R").findAny()); assertThat(exception).hasMessageContaining("Invalid enum constant name(s) in"); } @Test void invalidPatternIsDetected() { Exception exception = assertThrows(PreconditionViolationException.class, - () -> provideArguments(EnumWithTwoConstants.class, Mode.MATCH_ALL, "(", ")").findAny()); + () -> provideArguments(EnumWithFourConstants.class, Mode.MATCH_ALL, "(", ")").findAny()); assertThat(exception).hasMessageContaining("Pattern compilation failed"); } @Test void providesEnumConstantsBasedOnTestMethod() throws Exception { when(extensionContext.getRequiredTestMethod()).thenReturn( - TestCase.class.getDeclaredMethod("methodWithCorrectParameter", EnumWithTwoConstants.class)); + TestCase.class.getDeclaredMethod("methodWithCorrectParameter", EnumWithFourConstants.class)); var arguments = provideArguments(NullEnum.class); - assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }); + assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }, new Object[] { BAZ }, + new Object[] { QUX }); } @Test @@ -104,8 +108,64 @@ void methodsWithoutParametersAreDetected() throws Exception { assertThat(exception).hasMessageStartingWith("Test method must declare at least one parameter"); } + @Test + void providesEnumConstantsStartingFromBar() { + var arguments = provideArguments(EnumWithFourConstants.class, "BAR", "", Mode.INCLUDE); + + assertThat(arguments).containsExactly(new Object[] { BAR }, new Object[] { BAZ }, new Object[] { QUX }); + } + + @Test + void providesEnumConstantsEndingAtBaz() { + var arguments = provideArguments(EnumWithFourConstants.class, "", "BAZ", Mode.INCLUDE); + + assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAR }, new Object[] { BAZ }); + } + + @Test + void providesEnumConstantsFromBarToBaz() { + var arguments = provideArguments(EnumWithFourConstants.class, "BAR", "BAZ", Mode.INCLUDE); + + assertThat(arguments).containsExactly(new Object[] { BAR }, new Object[] { BAZ }); + } + + @Test + void providesEnumConstantsFromFooToBazWhileExcludingBar() { + var arguments = provideArguments(EnumWithFourConstants.class, "FOO", "BAZ", Mode.EXCLUDE, "BAR"); + + assertThat(arguments).containsExactly(new Object[] { FOO }, new Object[] { BAZ }); + } + + @Test + void providesNoEnumConstant() { + var arguments = provideArguments(EnumWithNoConstant.class); + + assertThat(arguments).isEmpty(); + } + + @Test + void invalidConstantNameIsDetectedInRange() { + Exception exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(EnumWithFourConstants.class, "FOO", "BAZ", Mode.EXCLUDE, "QUX").findAny()); + assertThat(exception).hasMessageContaining("Invalid enum constant name(s) in"); + } + + @Test + void invalidStartingRangeIsDetected() { + Exception exception = assertThrows(IllegalArgumentException.class, + () -> provideArguments(EnumWithFourConstants.class, "B4R", "", Mode.INCLUDE).findAny()); + assertThat(exception).hasMessageContaining("No enum constant"); + } + + @Test + void invalidEndingRangeIsDetected() { + Exception exception = assertThrows(IllegalArgumentException.class, + () -> provideArguments(EnumWithFourConstants.class, "", "B4R", Mode.INCLUDE).findAny()); + assertThat(exception).hasMessageContaining("No enum constant"); + } + static class TestCase { - void methodWithCorrectParameter(EnumWithTwoConstants parameter) { + void methodWithCorrectParameter(EnumWithFourConstants parameter) { } void methodWithIncorrectParameter(Object parameter) { @@ -115,8 +175,11 @@ void methodWithoutParameters() { } } - enum EnumWithTwoConstants { - FOO, BAR + enum EnumWithFourConstants { + FOO, BAR, BAZ, QUX + } + + enum EnumWithNoConstant { } private > Stream provideArguments(Class enumClass, String... names) { @@ -124,12 +187,20 @@ private > Stream provideArguments(Class enumClass } private > Stream provideArguments(Class enumClass, Mode mode, String... names) { + return provideArguments(enumClass, "", "", mode, names); + } + + private > Stream provideArguments(Class enumClass, String from, String to, Mode mode, + String... names) { var annotation = mock(EnumSource.class); when(annotation.value()).thenAnswer(invocation -> enumClass); + when(annotation.from()).thenAnswer(invocation -> from); + when(annotation.to()).thenAnswer(invocation -> to); when(annotation.mode()).thenAnswer(invocation -> mode); when(annotation.names()).thenAnswer(invocation -> names); - when(annotation.toString()).thenReturn(String.format("@EnumSource(value=%s.class, mode=%s, names=%s)", - enumClass.getSimpleName(), mode, Arrays.toString(names))); + when(annotation.toString()).thenReturn( + String.format("@EnumSource(value=%s.class, from=%s, to=%s, mode=%s, names=%s)", enumClass.getSimpleName(), + from, to, mode, Arrays.toString(names))); var provider = new EnumArgumentsProvider(); provider.accept(annotation); From 07806ad09b31b33c7cc5ec197cebd6a2c32565a7 Mon Sep 17 00:00:00 2001 From: yhkuo41 Date: Fri, 3 Jan 2025 22:04:51 +0800 Subject: [PATCH 2/3] Add validations for enum range selection Ensure `from` and `to` are empty when the enum has no constants, and validate `from` comes before `to` like `EnumSet.range`. Mark the `from` and `to` attributes as EXPERIMENTAL. Resolves #4185. --- .../test/java/example/ParameterizedTestDemo.java | 2 +- .../params/provider/EnumArgumentsProvider.java | 6 ++++++ .../junit/jupiter/params/provider/EnumSource.java | 12 ++++++++++++ .../provider/EnumArgumentsProviderTests.java | 14 ++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/documentation/src/test/java/example/ParameterizedTestDemo.java b/documentation/src/test/java/example/ParameterizedTestDemo.java index 4a200726ebcd..6f806e54aaf6 100644 --- a/documentation/src/test/java/example/ParameterizedTestDemo.java +++ b/documentation/src/test/java/example/ParameterizedTestDemo.java @@ -174,7 +174,7 @@ void testWithEnumSourceRegex(ChronoUnit unit) { // tag::EnumSource_range_exclude_example[] @ParameterizedTest - @EnumSource(mode = EXCLUDE, from = "HOURS", to = "DAYS", names = { "HALF_DAYS" }) + @EnumSource(from = "HOURS", to = "DAYS", mode = EXCLUDE, names = { "HALF_DAYS" }) void testWithEnumSourceRangeExclude(ChronoUnit unit) { assertTrue(EnumSet.of(ChronoUnit.HOURS, ChronoUnit.DAYS).contains(unit)); assertFalse(EnumSet.of(ChronoUnit.HALF_DAYS).contains(unit)); diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java index a68b43d5f371..606d02e19d64 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumArgumentsProvider.java @@ -45,10 +45,16 @@ private > Set getEnumConstants(ExtensionContext c Class enumClass = determineEnumClass(context, enumSource); E[] constants = enumClass.getEnumConstants(); if (constants.length == 0) { + Preconditions.condition(enumSource.from().isEmpty() && enumSource.to().isEmpty(), + "No enum constant in " + enumClass.getSimpleName() + ", but 'from' or 'to' is not empty."); return EnumSet.noneOf(enumClass); } E from = enumSource.from().isEmpty() ? constants[0] : Enum.valueOf(enumClass, enumSource.from()); E to = enumSource.to().isEmpty() ? constants[constants.length - 1] : Enum.valueOf(enumClass, enumSource.to()); + Preconditions.condition(from.compareTo(to) <= 0, + () -> String.format( + "Invalid enum range: 'from' (%s) must come before 'to' (%s) in the natural order of enum constants.", + from, to)); return EnumSet.range(from, to); } diff --git a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java index 673066b163b2..9c43c0ba465d 100644 --- a/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java +++ b/junit-jupiter-params/src/main/java/org/junit/jupiter/params/provider/EnumSource.java @@ -99,7 +99,10 @@ * @see #names * @see #to * @see #mode + * + * @since 5.12 */ + @API(status = EXPERIMENTAL, since = "5.12") String from() default ""; /** @@ -112,12 +115,19 @@ * @see #names * @see #from * @see #mode + * + * @since 5.12 */ + @API(status = EXPERIMENTAL, since = "5.12") String to() default ""; /** * The enum constant selection mode. * + *

The mode only applies to the {@link #names} attribute and does not change + * the behavior of {@link #from} and {@link #to}, which always define a range + * based on the natural order of the enum constants. + * *

Defaults to {@link Mode#INCLUDE INCLUDE}. * * @see Mode#INCLUDE @@ -126,6 +136,8 @@ * @see Mode#MATCH_ANY * @see Mode#MATCH_NONE * @see #names + * @see #from + * @see #to */ Mode mode() default Mode.INCLUDE; diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java index a3c405dcf23b..b7dc9e3cb5bf 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java @@ -164,6 +164,20 @@ void invalidEndingRangeIsDetected() { assertThat(exception).hasMessageContaining("No enum constant"); } + @Test + void invalidRangeOrderIsDetected() { + Exception exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(EnumWithFourConstants.class, "BAR", "FOO", Mode.INCLUDE).findAny()); + assertThat(exception).hasMessageContaining("Invalid enum range"); + } + + @Test + void invalidRangeIsDetectedWhenEnumWithNoConstantIsProvided() { + Exception exception = assertThrows(PreconditionViolationException.class, + () -> provideArguments(EnumWithNoConstant.class, "BAR", "FOO", Mode.INCLUDE).findAny()); + assertThat(exception).hasMessageContaining("No enum constant"); + } + static class TestCase { void methodWithCorrectParameter(EnumWithFourConstants parameter) { } From 427dc011a60e99aae37f67a9dbdf8832579d882b Mon Sep 17 00:00:00 2001 From: Marc Philipp Date: Wed, 8 Jan 2025 10:55:01 +0100 Subject: [PATCH 3/3] Polish tests --- .../provider/EnumArgumentsProviderTests.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java index 3fd33e296e99..8d2d5cfbd170 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/params/provider/EnumArgumentsProviderTests.java @@ -58,21 +58,21 @@ void provideAllEnumConstantsWithNamingAll() { @Test void duplicateConstantNameIsDetected() { - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(EnumWithFourConstants.class, "FOO", "BAR", "FOO").findAny()); assertThat(exception).hasMessageContaining("Duplicate enum constant name(s) found"); } @Test void invalidConstantNameIsDetected() { - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(EnumWithFourConstants.class, "FO0", "B4R").findAny()); assertThat(exception).hasMessageContaining("Invalid enum constant name(s) in"); } @Test void invalidPatternIsDetected() { - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(EnumWithFourConstants.class, Mode.MATCH_ALL, "(", ")").findAny()); assertThat(exception).hasMessageContaining("Pattern compilation failed"); } @@ -93,7 +93,7 @@ void incorrectParameterTypeIsDetected() throws Exception { when(extensionContext.getRequiredTestMethod()).thenReturn( TestCase.class.getDeclaredMethod("methodWithIncorrectParameter", Object.class)); - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(NullEnum.class).findAny()); assertThat(exception).hasMessageStartingWith("First parameter must reference an Enum type"); } @@ -103,7 +103,7 @@ void methodsWithoutParametersAreDetected() throws Exception { when(extensionContext.getRequiredTestMethod()).thenReturn( TestCase.class.getDeclaredMethod("methodWithoutParameters")); - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(NullEnum.class).findAny()); assertThat(exception).hasMessageStartingWith("Test method must declare at least one parameter"); } @@ -145,35 +145,35 @@ void providesNoEnumConstant() { @Test void invalidConstantNameIsDetectedInRange() { - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(EnumWithFourConstants.class, "FOO", "BAZ", Mode.EXCLUDE, "QUX").findAny()); assertThat(exception).hasMessageContaining("Invalid enum constant name(s) in"); } @Test void invalidStartingRangeIsDetected() { - Exception exception = assertThrows(IllegalArgumentException.class, + var exception = assertThrows(IllegalArgumentException.class, () -> provideArguments(EnumWithFourConstants.class, "B4R", "", Mode.INCLUDE).findAny()); assertThat(exception).hasMessageContaining("No enum constant"); } @Test void invalidEndingRangeIsDetected() { - Exception exception = assertThrows(IllegalArgumentException.class, + var exception = assertThrows(IllegalArgumentException.class, () -> provideArguments(EnumWithFourConstants.class, "", "B4R", Mode.INCLUDE).findAny()); assertThat(exception).hasMessageContaining("No enum constant"); } @Test void invalidRangeOrderIsDetected() { - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(EnumWithFourConstants.class, "BAR", "FOO", Mode.INCLUDE).findAny()); assertThat(exception).hasMessageContaining("Invalid enum range"); } @Test void invalidRangeIsDetectedWhenEnumWithNoConstantIsProvided() { - Exception exception = assertThrows(PreconditionViolationException.class, + var exception = assertThrows(PreconditionViolationException.class, () -> provideArguments(EnumWithNoConstant.class, "BAR", "FOO", Mode.INCLUDE).findAny()); assertThat(exception).hasMessageContaining("No enum constant"); } @@ -207,11 +207,11 @@ private > Stream provideArguments(Class enumClass private > Stream provideArguments(Class enumClass, String from, String to, Mode mode, String... names) { var annotation = mock(EnumSource.class); - when(annotation.value()).thenAnswer(invocation -> enumClass); - when(annotation.from()).thenAnswer(invocation -> from); - when(annotation.to()).thenAnswer(invocation -> to); - when(annotation.mode()).thenAnswer(invocation -> mode); - when(annotation.names()).thenAnswer(invocation -> names); + when(annotation.value()).thenAnswer(__ -> enumClass); + when(annotation.from()).thenReturn(from); + when(annotation.to()).thenReturn(to); + when(annotation.mode()).thenReturn(mode); + when(annotation.names()).thenReturn(names); when(annotation.toString()).thenReturn( String.format("@EnumSource(value=%s.class, from=%s, to=%s, mode=%s, names=%s)", enumClass.getSimpleName(), from, to, mode, Arrays.toString(names)));