Skip to content

Commit

Permalink
Add validations for enum range selection
Browse files Browse the repository at this point in the history
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 junit-team#4185.
  • Loading branch information
yhkuo41 committed Jan 3, 2025
1 parent 56557dc commit 07806ad
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,16 @@ private <E extends Enum<E>> Set<? extends E> getEnumConstants(ExtensionContext c
Class<E> 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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@
* @see #names
* @see #to
* @see #mode
*
* @since 5.12
*/
@API(status = EXPERIMENTAL, since = "5.12")
String from() default "";

/**
Expand All @@ -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.
*
* <p>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.
*
* <p>Defaults to {@link Mode#INCLUDE INCLUDE}.
*
* @see Mode#INCLUDE
Expand All @@ -126,6 +136,8 @@
* @see Mode#MATCH_ANY
* @see Mode#MATCH_NONE
* @see #names
* @see #from
* @see #to
*/
Mode mode() default Mode.INCLUDE;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
}
Expand Down

0 comments on commit 07806ad

Please sign in to comment.