diff --git a/documentation/src/test/java/example/ConditionalTestExecutionDemo.java b/documentation/src/test/java/example/ConditionalTestExecutionDemo.java index 5d9e68eaa5a4..f63f4aedf7a7 100644 --- a/documentation/src/test/java/example/ConditionalTestExecutionDemo.java +++ b/documentation/src/test/java/example/ConditionalTestExecutionDemo.java @@ -12,6 +12,8 @@ import static org.junit.jupiter.api.condition.JRE.JAVA_10; import static org.junit.jupiter.api.condition.JRE.JAVA_11; +import static org.junit.jupiter.api.condition.JRE.JAVA_17; +import static org.junit.jupiter.api.condition.JRE.JAVA_18; import static org.junit.jupiter.api.condition.JRE.JAVA_8; import static org.junit.jupiter.api.condition.JRE.JAVA_9; import static org.junit.jupiter.api.condition.OS.LINUX; @@ -23,6 +25,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledForJreRange; import org.junit.jupiter.api.condition.DisabledIf; @@ -38,6 +41,7 @@ import org.junit.jupiter.api.condition.EnabledInNativeImage; import org.junit.jupiter.api.condition.EnabledOnJre; import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.JRE; class ConditionalTestExecutionDemo { @@ -99,6 +103,16 @@ void notOnNewMacs() { } // end::user_guide_architecture[] + @Test + @EnabledOnJre(value = { JAVA_17, JAVA_18 }, versions = { 20, 21 }) + void onJava17or18or20or21() { + } + + @Test + @EnabledOnJre(versions = 21) + void onlyOnJava21() { + } + // tag::user_guide_jre[] @Test @EnabledOnJre(JAVA_8) @@ -124,6 +138,45 @@ void fromJava9toCurrentJavaFeatureNumber() { // ... } + @Test + @EnabledForJreRange(minVersion = 10) + void fromJava10toCurrentJavaFeatureNumber() { + // ... + } + + @Test + @EnabledForJreRange(minVersion = 25) + void fromJava25toCurrentJavaFeatureNumber() { + // ... + } + + @Disabled("DEMO: intended to fail") + @Test + @EnabledForJreRange(minVersion = 99, max = JRE.JAVA_17) + void fromJava99toJava17() { + // ... + } + + @Disabled("DEMO: intended to fail") + @Test + @EnabledForJreRange(min = JAVA_11, minVersion = 10) + void competingJreAndMinFeatureVersions() { + // ... + } + + @Disabled("DEMO: intended to fail") + @Test + @EnabledForJreRange(max = JAVA_11, maxVersion = 10) + void competingJreAndMaxFeatureVersions() { + // ... + } + + @Test + @EnabledForJreRange(minVersion = 10, maxVersion = 25) + void fromJava17to25() { + // ... + } + @Test @EnabledForJreRange(max = JAVA_11) void fromJava8To11() { diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java index fc96d82118b0..26744999db46 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRange.java @@ -10,6 +10,7 @@ package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -24,7 +25,11 @@ /** * {@code @DisabledForJreRange} is used to signal that the annotated test class * or test method is disabled for a specific range of Java Runtime - * Environment (JRE) versions from {@link #min} to {@link #max}. + * Environment (JRE) versions. + * + *

Version ranges can be specified as {@link JRE} enum constants via {@link #min} + * and {@link #max} or as integers via {@link #minFeatureVersion} and + * {@link #maxFeatureVersion}. * *

When applied at the class level, all test methods within that class will * be disabled on the same specified JRE versions. @@ -82,29 +87,75 @@ public @interface DisabledForJreRange { /** - * Java Runtime Environment version which is used as the lower boundary - * for the version range that determines if the annotated class or method - * should be disabled. + * Java Runtime Environment version which is used as the lower boundary for + * the version range that determines if the annotated class or method should + * be disabled, specified as a {@link JRE} enum constant. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the minimum version via {@link #minVersion()} + * instead. * - *

Defaults to {@link JRE#JAVA_8 JAVA_8}, as this is the lowest - * supported JRE version. + *

Defaults to {@link JRE#JAVA_8 JAVA_8}, as this is the lowest supported + * JRE version. * * @see JRE + * @see #minVersion() */ JRE min() default JRE.JAVA_8; /** - * Java Runtime Environment version which is used as the upper boundary - * for the version range that determines if the annotated class or method - * should be disabled. + * Java Runtime Environment version which is used as the upper boundary for + * the version range that determines if the annotated class or method should + * be disabled, specified as a {@link JRE} enum constant. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the maximum version via {@link #maxVersion()} + * instead. * *

Defaults to {@link JRE#OTHER OTHER}, as this will always be the highest * possible version. * * @see JRE + * @see #maxVersion() */ JRE max() default JRE.OTHER; + /** + * Java Runtime Environment version which is used as the lower boundary for + * the version range that determines if the annotated class or method should + * be disabled, specified as an integer. + * + *

If a {@code JRE} enum constant exists for the particular JRE version, + * you can specify the minimum version via {@link #min()} instead. + * + *

Defaults to {@code -1} to signal that {@link #min()} should be used instead. + * + * @since 5.12 + * @see #min() + * @see JRE#featureVersion() + * @see Runtime.Version#feature() + */ + @API(status = EXPERIMENTAL, since = "5.12") + int minVersion() default -1; + + /** + * Java Runtime Environment version which is used as the upper boundary for + * the version range that determines if the annotated class or method should + * be disabled, specified as an integer. + * + *

If a {@code JRE} enum constant exists for the particular JRE version, + * you can specify the maximum version via {@link #max()} instead. + * + *

Defaults to {@code -1} to signal that {@link #max()} should be used instead. + * + * @since 5.12 + * @see #max() + * @see JRE#featureVersion() + * @see Runtime.Version#feature() + */ + @API(status = EXPERIMENTAL, since = "5.12") + int maxVersion() default -1; + /** * Custom reason to provide if the test or container is disabled. * diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRangeCondition.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRangeCondition.java index b62e7053c4de..1f74ab51749a 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRangeCondition.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledForJreRangeCondition.java @@ -31,13 +31,25 @@ class DisabledForJreRangeCondition extends BooleanExecutionCondition= 0, - "@DisabledForJreRange.min must be less than or equal to @DisabledForJreRange.max"); + JRE minJre = annotation.min(); + JRE maxJre = annotation.max(); + int minFeatureVersion = annotation.minVersion(); + int maxFeatureVersion = annotation.maxVersion(); + + Preconditions.condition(!(minJre != JRE.JAVA_8 && minFeatureVersion != -1), + "@DisabledForJreRange's minimum value must be configured with either a JRE or feature version, but not both"); + Preconditions.condition(!(maxJre != JRE.OTHER && maxFeatureVersion != -1), + "@DisabledForJreRange's maximum value must be configured with either a JRE or feature version, but not both"); + + boolean minValueConfigured = minJre != JRE.JAVA_8 || minFeatureVersion != -1; + boolean maxValueConfigured = maxJre != JRE.OTHER || maxFeatureVersion != -1; + Preconditions.condition(minValueConfigured || maxValueConfigured, + "You must declare a non-default value for the minimum or maximum value in @DisabledForJreRange"); + + int min = (minFeatureVersion != -1 ? minFeatureVersion : minJre.featureVersion()); + int max = (maxFeatureVersion != -1 ? maxFeatureVersion : maxJre.featureVersion()); + Preconditions.condition(min <= max, + "@DisabledForJreRange's minimum value must be less than or equal to its maximum value"); return !JRE.isCurrentVersionWithinRange(min, max); } diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java index 6231f5246067..8b06ea87ac13 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJre.java @@ -10,6 +10,7 @@ package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -24,7 +25,10 @@ /** * {@code @DisabledOnJre} is used to signal that the annotated test class or * test method is disabled on one or more specified Java Runtime - * Environment (JRE) {@linkplain #value versions}. + * Environment (JRE) versions. + * + *

Versions can be specified as {@link JRE} enum constants via {@link #value()} + * or as integers via {@link #versions()}. * *

When applied at the class level, all test methods within that class * will be disabled on the same specified JRE versions. @@ -82,12 +86,31 @@ public @interface DisabledOnJre { /** - * Java Runtime Environment versions on which the annotated class or - * method should be disabled. + * Java Runtime Environment versions on which the annotated class or method + * should be disabled, specified as {@link JRE} enum constants. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the version via {@link #versions()} instead. * * @see JRE + * @see #versions() + */ + JRE[] value() default {}; + + /** + * Java Runtime Environment versions on which the annotated class or method + * should be disabled, specified as integers. + * + *

If a {@code JRE} enum constant exists for a particular JRE version, you + * can specify the version via {@link #value()} instead. + * + * @since 5.12 + * @see #value() + * @see JRE#featureVersion() + * @see Runtime.Version#feature() */ - JRE[] value(); + @API(status = EXPERIMENTAL, since = "5.12") + int[] versions() default {}; /** * Custom reason to provide if the test or container is disabled. diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJreCondition.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJreCondition.java index aa74770bc3cd..44c60317732f 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJreCondition.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/DisabledOnJreCondition.java @@ -32,9 +32,12 @@ class DisabledOnJreCondition extends BooleanExecutionCondition { @Override boolean isEnabled(DisabledOnJre annotation) { - JRE[] versions = annotation.value(); - Preconditions.condition(versions.length > 0, "You must declare at least one JRE in @DisabledOnJre"); - return Arrays.stream(versions).noneMatch(JRE::isCurrentVersion); + JRE[] jres = annotation.value(); + int[] featureVersions = annotation.versions(); + Preconditions.condition(jres.length > 0 || featureVersions.length > 0, + "You must declare at least one JRE or version in @DisabledOnJre"); + return Arrays.stream(jres).noneMatch(JRE::isCurrentVersion) + && Arrays.stream(featureVersions).noneMatch(JRE::isCurrentFeatureVersion); } } diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java index 79ef2aeb595e..fc19101e3aab 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRange.java @@ -10,6 +10,7 @@ package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -24,7 +25,11 @@ /** * {@code @EnabledForJreRange} is used to signal that the annotated test class or * test method is only enabled for a specific range of Java Runtime - * Environment (JRE) versions from {@link #min} to {@link #max}. + * Environment (JRE) versions. + * + *

Version ranges can be specified as {@link JRE} enum constants via {@link #min} + * and {@link #max} or as integers via {@link #minFeatureVersion} and + * {@link #maxFeatureVersion}. * *

When applied at the class level, all test methods within that class will * be enabled on the same specified JRE versions. @@ -82,29 +87,75 @@ public @interface EnabledForJreRange { /** - * Java Runtime Environment version which should be used as the lower boundary - * for the version range that determines if the annotated class or method - * should be enabled. + * Java Runtime Environment version which is used as the lower boundary for + * the version range that determines if the annotated class or method should + * be enabled, specified as a {@link JRE} enum constant. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the minimum version via {@link #minVersion()} + * instead. * - *

Defaults to {@link JRE#JAVA_8 JAVA_8}, as this is the lowest - * supported JRE version. + *

Defaults to {@link JRE#JAVA_8 JAVA_8}, as this is the lowest supported + * JRE version. * * @see JRE + * @see #minVersion() */ JRE min() default JRE.JAVA_8; /** - * Java Runtime Environment version which should be used as the upper boundary - * for the version range that determines if the annotated class or method - * should be enabled. + * Java Runtime Environment version which is used as the upper boundary for + * the version range that determines if the annotated class or method should + * be enabled, specified as a {@link JRE} enum constant. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the maximum version via {@link #maxVersion()} + * instead. * *

Defaults to {@link JRE#OTHER OTHER}, as this will always be the highest * possible version. * * @see JRE + * @see #maxVersion() */ JRE max() default JRE.OTHER; + /** + * Java Runtime Environment version which is used as the lower boundary for + * the version range that determines if the annotated class or method should + * be enabled, specified as an integer. + * + *

If a {@code JRE} enum constant exists for the particular JRE version, + * you can specify the minimum version via {@link #min()} instead. + * + *

Defaults to {@code -1} to signal that {@link #min()} should be used instead. + * + * @since 5.12 + * @see #min() + * @see JRE#featureVersion() + * @see Runtime.Version#feature() + */ + @API(status = EXPERIMENTAL, since = "5.12") + int minVersion() default -1; + + /** + * Java Runtime Environment version which is used as the upper boundary for + * the version range that determines if the annotated class or method should + * be enabled, specified as an integer. + * + *

If a {@code JRE} enum constant exists for the particular JRE version, + * you can specify the maximum version via {@link #max()} instead. + * + *

Defaults to {@code -1} to signal that {@link #max()} should be used instead. + * + * @since 5.12 + * @see #max() + * @see JRE#featureVersion() + * @see Runtime.Version#feature() + */ + @API(status = EXPERIMENTAL, since = "5.12") + int maxVersion() default -1; + /** * Custom reason to provide if the test or container is disabled. * diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRangeCondition.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRangeCondition.java index abb5001a7ccf..a1a8a1a5cbb4 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRangeCondition.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledForJreRangeCondition.java @@ -31,13 +31,25 @@ class EnabledForJreRangeCondition extends BooleanExecutionCondition= 0, - "@EnabledForJreRange.min must be less than or equal to @EnabledForJreRange.max"); + JRE minJre = annotation.min(); + JRE maxJre = annotation.max(); + int minFeatureVersion = annotation.minVersion(); + int maxFeatureVersion = annotation.maxVersion(); + + Preconditions.condition(!(minJre != JRE.JAVA_8 && minFeatureVersion != -1), + "@EnabledForJreRange's minimum value must be configured with either a JRE or feature version, but not both"); + Preconditions.condition(!(maxJre != JRE.OTHER && maxFeatureVersion != -1), + "@EnabledForJreRange's maximum value must be configured with either a JRE or feature version, but not both"); + + boolean minValueConfigured = minJre != JRE.JAVA_8 || minFeatureVersion != -1; + boolean maxValueConfigured = maxJre != JRE.OTHER || maxFeatureVersion != -1; + Preconditions.condition(minValueConfigured || maxValueConfigured, + "You must declare a non-default value for the minimum or maximum value in @EnabledForJreRange"); + + int min = (minFeatureVersion != -1 ? minFeatureVersion : minJre.featureVersion()); + int max = (maxFeatureVersion != -1 ? maxFeatureVersion : maxJre.featureVersion()); + Preconditions.condition(min <= max, + "@EnabledForJreRange's minimum value must be less than or equal to its maximum value"); return JRE.isCurrentVersionWithinRange(min, max); } diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java index f768e439c18f..119efadc7f3f 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJre.java @@ -10,6 +10,7 @@ package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import java.lang.annotation.Documented; @@ -23,8 +24,11 @@ /** * {@code @EnabledOnJre} is used to signal that the annotated test class or - * test method is only enabled on one or more specified Java - * Runtime Environment (JRE) {@linkplain #value versions}. + * test method is only enabled on one or more specified Java Runtime + * Environment (JRE) versions. + * + *

Versions can be specified as {@link JRE} enum constants via {@link #value()} + * or as integers via {@link #versions()}. * *

When applied at the class level, all test methods within that class * will be enabled on the same specified JRE versions. @@ -82,12 +86,31 @@ public @interface EnabledOnJre { /** - * Java Runtime Environment versions on which the annotated class or - * method should be enabled. + * Java Runtime Environment versions on which the annotated class or method + * should be enabled, specified as {@link JRE} enum constants. + * + *

If a {@code JRE} enum constant does not exist for a particular JRE + * version, you can specify the version via {@link #versions()} instead. * * @see JRE + * @see #versions() + */ + JRE[] value() default {}; + + /** + * Java Runtime Environment versions on which the annotated class or method + * should be enabled, specified as integers. + * + *

If a {@code JRE} enum constant exists for a particular JRE version, you + * can specify the version via {@link #value()} instead. + * + * @since 5.12 + * @see #value() + * @see JRE#featureVersion() + * @see Runtime.Version#feature() */ - JRE[] value(); + @API(status = EXPERIMENTAL, since = "5.12") + int[] versions() default {}; /** * Custom reason to provide if the test or container is disabled. diff --git a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJreCondition.java b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJreCondition.java index 674d0687856c..f5e263abfeaa 100644 --- a/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJreCondition.java +++ b/junit-jupiter-api/src/main/java/org/junit/jupiter/api/condition/EnabledOnJreCondition.java @@ -35,9 +35,12 @@ class EnabledOnJreCondition extends BooleanExecutionCondition { @Override boolean isEnabled(EnabledOnJre annotation) { - JRE[] versions = annotation.value(); - Preconditions.condition(versions.length > 0, "You must declare at least one JRE in @EnabledOnJre"); - return Arrays.stream(versions).anyMatch(JRE::isCurrentVersion); + JRE[] jres = annotation.value(); + int[] featureVersions = annotation.versions(); + Preconditions.condition(jres.length > 0 || featureVersions.length > 0, + "You must declare at least one JRE or version in @EnabledOnJre"); + return Arrays.stream(jres).anyMatch(JRE::isCurrentVersion) + || Arrays.stream(featureVersions).anyMatch(JRE::isCurrentFeatureVersion); } } diff --git a/junit-jupiter-api/src/templates/resources/main/org/junit/jupiter/api/condition/JRE.java.jte b/junit-jupiter-api/src/templates/resources/main/org/junit/jupiter/api/condition/JRE.java.jte index 93479da1378f..7addde3fd176 100644 --- a/junit-jupiter-api/src/templates/resources/main/org/junit/jupiter/api/condition/JRE.java.jte +++ b/junit-jupiter-api/src/templates/resources/main/org/junit/jupiter/api/condition/JRE.java.jte @@ -7,10 +7,10 @@ ${licenseHeader} package org.junit.jupiter.api.condition; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import java.lang.reflect.Method; -import java.util.EnumSet; import org.apiguardian.api.API; import org.junit.platform.commons.logging.Logger; @@ -49,7 +49,7 @@ public enum JRE { @if(jre.getSince() != null)<%-- --%>@API(status = STABLE, since = "${jre.getSince()}") @endif<%-- ---%>JAVA_${jre.getVersion()}, +--%>JAVA_${jre.getVersion()}(${jre.getVersion()}), @endfor /** * A JRE version other than <%-- @@ -61,13 +61,17 @@ public enum JRE { * @elseif(!jre.isLast()) @endif<%-- --%>@endfor */ - OTHER; + OTHER(Integer.MAX_VALUE); private static final Logger logger = LoggerFactory.getLogger(JRE.class); - private static final JRE CURRENT_VERSION = determineCurrentVersion(); + private static final int UNKNOWN_FEATURE_VERSION = -1; - private static JRE determineCurrentVersion() { + private static final int CURRENT_FEATURE_VERSION = determineCurrentFeatureVersion(); + + private static final JRE CURRENT_VERSION = determineCurrentVersion(CURRENT_FEATURE_VERSION); + + private static int determineCurrentFeatureVersion() { String javaVersion = System.getProperty("java.version"); boolean javaVersionIsBlank = StringUtils.isBlank(javaVersion); @@ -77,7 +81,7 @@ public enum JRE { } if (!javaVersionIsBlank && javaVersion.startsWith("1.8")) { - return JAVA_8; + return 8; } try { @@ -87,48 +91,103 @@ public enum JRE { Method versionMethod = Runtime.class.getMethod("version"); Object version = ReflectionSupport.invokeMethod(versionMethod, null); Method majorMethod = version.getClass().getMethod("major"); - int major = (int) ReflectionSupport.invokeMethod(majorMethod, version); - switch (major) {<%-- - --%>@for(var jre : jres)<%-- - --%>@if(jre.getVersion() != 8) - case ${jre.getVersion()}: - return JAVA_${jre.getVersion()};<%-- - --%>@endif<%-- - --%>@endfor - default: - return OTHER; - } + return (int) ReflectionSupport.invokeMethod(majorMethod, version); } catch (Exception ex) { logger.debug(ex, () -> "Failed to determine the current JRE version via java.lang.Runtime.Version."); } - // null signals that the current JRE version is "unknown" - return null; + return UNKNOWN_FEATURE_VERSION; + } + + private static JRE determineCurrentVersion(int currentFeatureVersion) { + switch (currentFeatureVersion) { + case UNKNOWN_FEATURE_VERSION: + // null signals that the current JRE version is "unknown" + return null;<%-- + --%>@for(var jre : jres) + case ${jre.getVersion()}: + return JAVA_${jre.getVersion()};<%-- + --%>@endfor + default: + return OTHER; + } + } + + private final int featureVersion; + + private JRE(int featureVersion) { + this.featureVersion = featureVersion; } /** * @return {@code true} if this {@code JRE} is known to be the * Java Runtime Environment version for the currently executing JVM or if * the version is {@link #OTHER} + * + * @see #currentVersion() + * @see #currentFeatureVersion() */ public boolean isCurrentVersion() { return this == CURRENT_VERSION; } + /** + * Get the feature version of this {@code JRE}. + * + * @return the feature version of this {@code JRE}, or + * {@link Integer#MAX_VALUE} if this {@code JRE} is {@link #OTHER} + * + * @since 5.12 + * @see Runtime.Version#feature() + * @see #currentFeatureVersion() + */ + @API(status = EXPERIMENTAL, since = "5.12") + public int featureVersion() { + return this.featureVersion; + } + /** * @return the {@link JRE} for the currently executing JVM, potentially * {@link #OTHER} * * @since 5.7 + * @see #currentFeatureVersion() */ @API(status = STABLE, since = "5.7") public static JRE currentVersion() { return CURRENT_VERSION; } - static boolean isCurrentVersionWithinRange(JRE min, JRE max) { - return EnumSet.range(min, max).contains(CURRENT_VERSION); + /** + * @return the feature version for the currently executing JVM, or + * {@code -1} to signal that the feature version is unknown + * + * @since 5.12 + * @see Runtime.Version#feature() + * @see #currentVersion() + */ + @API(status = EXPERIMENTAL, since = "5.12") + public static int currentFeatureVersion() { + return CURRENT_FEATURE_VERSION; + } + + /** + * @return {@code true} if the supplied feature version is known to be + * the Java Runtime Environment version for the currently executing JVM + * or if the supplied feature version is {@code -1} and the feature + * version of the current JVM is unknown + * + * @since 5.12 + * @see Runtime.Version#feature() + */ + @API(status = EXPERIMENTAL, since = "5.12") + public static boolean isCurrentFeatureVersion(int featureVersion) { + return featureVersion == CURRENT_FEATURE_VERSION; + } + + static boolean isCurrentVersionWithinRange(int min, int max) { + return CURRENT_FEATURE_VERSION >= min && CURRENT_FEATURE_VERSION <= max; } } diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeConditionTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeConditionTests.java index cfcd7fcdd9b5..8ae3bed46058 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeConditionTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/DisabledForJreRangeConditionTests.java @@ -66,7 +66,8 @@ void enabledBecauseAnnotationIsNotPresent() { void defaultValues() { assertThatExceptionOfType(PreconditionViolationException.class)// .isThrownBy(this::evaluateCondition)// - .withMessageContaining("You must declare a non-default value for min or max in @DisabledForJreRange"); + .withMessageContaining( + "You must declare a non-default value for the minimum or maximum value in @DisabledForJreRange"); } /** diff --git a/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeConditionTests.java b/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeConditionTests.java index 4bb80e722c6d..80111e2090f5 100644 --- a/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeConditionTests.java +++ b/jupiter-tests/src/test/java/org/junit/jupiter/api/condition/EnabledForJreRangeConditionTests.java @@ -66,7 +66,8 @@ void enabledBecauseAnnotationIsNotPresent() { void defaultValues() { assertThatExceptionOfType(PreconditionViolationException.class)// .isThrownBy(this::evaluateCondition)// - .withMessageContaining("You must declare a non-default value for min or max in @EnabledForJreRange"); + .withMessageContaining( + "You must declare a non-default value for the minimum or maximum value in @EnabledForJreRange"); } /**