Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update code to Java 11 #707

Merged
merged 13 commits into from
May 2, 2023
4 changes: 4 additions & 0 deletions .infra/checkstyle/checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
<module name="ImportControl">
<property name="file" value="${config_loc}/import-control.xml" />
</module>
<module name="RegexpSinglelineJava">
<property name="format" value="import java.util.stream.Collectors;"/>
<property name="message" value="Collectors must be statically imported"/>
</module>
</module>
<module name="JavadocPackage" />
<module name="SuppressWarningsFilter" />
Expand Down
3 changes: 0 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,6 @@ tasks {
// See https://docs.gradle.org/current/userguide/java_testing.html#sec:java_testing_modular_patching
val patchModuleArg = "--patch-module=$moduleName=${compileJava.get().destinationDirectory.asFile.get().path}"
val testJvmArgs = listOf(
// Ignore these options on Java 8
"-XX:+IgnoreUnrecognizedVMOptions",
// EnvironmentVariableUtils: make java.util.Map accessible
"--add-opens=java.base/java.util=$moduleName",
// EnvironmentVariableUtils: make java.lang.System accessible
Expand Down Expand Up @@ -301,7 +299,6 @@ tasks {
filter {
includeTestsMatching("*Demo")
}
jvmArgs(testJvmArgs)
beatngu13 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/demo/java/org/junitpioneer/vintage/VintageTestDemo.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@

package org.junitpioneer.vintage;

import java.util.ArrayList;
import java.util.List;

public class VintageTestDemo {

// tag::vintage_test_indexoutofbound_exception[]
@Test(expected = IndexOutOfBoundsException.class)
public void outOfBounds_passes() {
new ArrayList<Object>().get(1);
List.of().get(1);
}
// end::vintage_test_indexoutofbound_exception[]

// tag::vintage_test_runtime_exception[]
@Test(expected = RuntimeException.class)
public void outOfBounds_passes_too() {
new ArrayList<Object>().get(1);
List.of().get(1);
}
// end::vintage_test_runtime_exception[]

Expand All @@ -33,7 +33,7 @@ class TheseTestsWillFailIntentionally {
// tag::vintage_test_iae_exception[]
@Test(expected = IllegalArgumentException.class)
public void outOfBounds_fails() {
new ArrayList<Object>().get(1);
List.of().get(1);
}
// end::vintage_test_iae_exception[]

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
*
* <p>Pioneer does not limit itself to proven ideas with wide application but is purposely open to
* experimentation. It aims to spin off successful and cohesive portions into sibling projects or back
* into the JUnit 5 code base.
* into the JUnit 5 code base.</p>
*
* <p>The dependencies on Jupiter modules could be marked as <code>transitive</code> but that would
* allow users who depend on this module to not `require` org.junit.*, which would be backwards.
* allow users who depend on this module to not `require` org.junit.*, which would be backwards.</p>
*/
module org.junitpioneer {
// see Javadoc for why these aren't transitive
Expand Down
40 changes: 20 additions & 20 deletions src/main/java/org/junitpioneer/internal/PioneerAnnotationUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

package org.junitpioneer.internal;

import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.toUnmodifiableList;
Michael1993 marked this conversation as resolved.
Show resolved Hide resolved

import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
Expand All @@ -20,10 +23,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.jupiter.api.extension.ExtensionContext;
Expand All @@ -34,9 +35,9 @@
/**
* Pioneer-internal utility class to handle annotations.
* DO NOT USE THIS CLASS - IT MAY CHANGE SIGNIFICANTLY IN ANY MINOR UPDATE.
*
* <p>
* It uses the following terminology to describe annotations that are not
* immediately present on an element:
* immediately present on an element:</p>
*
* <ul>
* <li><em>indirectly present</em> if a supertype of the element is annotated</li>
Expand All @@ -45,9 +46,11 @@
* {@link org.junit.jupiter.api.Nested @Nested}) is annotated</li>
* </ul>
*
* <p>
* All of the above mechanisms apply recursively, meaning that, e.g., for an annotation to be
* <em>meta-present</em> it can present on an annotation that is present on another annotation
* that is present on the element.
* </p>
*/
public class PioneerAnnotationUtils {

Expand Down Expand Up @@ -133,7 +136,7 @@ public static <A extends Annotation> List<Annotation> findAnnotatedAnnotations(A
// flatten @Repeatable aggregator annotations
.flatMap(PioneerAnnotationUtils::flatten)
.filter(a -> !(findOnType(a.annotationType(), annotation, isRepeatable, false).isEmpty()))
.collect(Collectors.toList());
.collect(toUnmodifiableList());
}

private static Stream<Annotation> flatten(Annotation annotation) {
Expand Down Expand Up @@ -183,7 +186,7 @@ static <A extends Annotation> Stream<A> findAnnotations(ExtensionContext context
List<A> onMethod = context
.getTestMethod()
.map(method -> findOnMethod(method, annotationType, findRepeated))
.orElse(Collections.emptyList());
.orElse(List.of());
if (!findAllEnclosing && !onMethod.isEmpty())
return onMethod.stream();
Stream<A> onClass = findOnOuterClasses(context.getTestClass(), annotationType, findRepeated, findAllEnclosing);
Expand All @@ -196,15 +199,12 @@ private static <A extends Annotation> List<A> findOnMethod(Method element, Class
if (findRepeated)
return AnnotationSupport.findRepeatableAnnotations(element, annotationType);
else
return AnnotationSupport
.findAnnotation(element, annotationType)
.map(Collections::singletonList)
.orElse(Collections.emptyList());
return AnnotationSupport.findAnnotation(element, annotationType).stream().collect(toUnmodifiableList());
}

private static <A extends Annotation> Stream<A> findOnOuterClasses(Optional<Class<?>> type, Class<A> annotationType,
boolean findRepeated, boolean findAllEnclosing) {
if (!type.isPresent())
if (type.isEmpty())
return Stream.empty();

List<A> onThisClass = Arrays.asList(type.get().getAnnotationsByType(annotationType));
Expand All @@ -220,18 +220,18 @@ private static <A extends Annotation> Stream<A> findOnOuterClasses(Optional<Clas
private static <A extends Annotation> List<A> findOnType(Class<?> element, Class<A> annotationType,
boolean findRepeated, boolean findAllEnclosing) {
if (element == null || element == Object.class)
return Collections.emptyList();
return List.of();
if (findRepeated)
return AnnotationSupport.findRepeatableAnnotations(element, annotationType);

List<A> onElement = AnnotationSupport
.findAnnotation(element, annotationType)
.map(Collections::singletonList)
.orElse(Collections.emptyList());
.stream()
.collect(toUnmodifiableList());
List<A> onInterfaces = Arrays
.stream(element.getInterfaces())
.flatMap(clazz -> findOnType(clazz, annotationType, false, findAllEnclosing).stream())
.collect(Collectors.toList());
.collect(toUnmodifiableList());
if (!annotationType.isAnnotationPresent(Inherited.class)) {
if (!findAllEnclosing)
return onElement;
Expand All @@ -240,23 +240,23 @@ private static <A extends Annotation> List<A> findOnType(Class<?> element, Class
.of(onElement, onInterfaces)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
.collect(toUnmodifiableList());
}
List<A> onSuperclass = findOnType(element.getSuperclass(), annotationType, false, findAllEnclosing);
return Stream
.of(onElement, onInterfaces, onSuperclass)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
.collect(toUnmodifiableList());
}

public static List<Annotation> findParameterArgumentsSources(Method testMethod) {
return Arrays
.stream(testMethod.getParameters())
.map(PioneerAnnotationUtils::collectArgumentSources)
.filter(list -> !list.isEmpty())
.filter(not(List::isEmpty))
.map(annotations -> annotations.get(0))
.collect(Collectors.toList());
.collect(toUnmodifiableList());
}

private static List<Annotation> collectArgumentSources(Parameter parameter) {
Expand All @@ -274,7 +274,7 @@ public static List<Annotation> findMethodArgumentsSources(Method testMethod) {
.filter(annotation -> AnnotationSupport
.findAnnotation(annotation.annotationType(), CartesianArgumentsSource.class)
.isPresent())
.collect(Collectors.toList());
.collect(toUnmodifiableList());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private PioneerPreconditions() {
* @return the supplied string
*/
public static String notBlank(String str, String message) {
if (str == null || str.trim().isEmpty()) {
if (str == null || str.isBlank()) {
throw new PreconditionViolationException(message);
}

Expand All @@ -46,7 +46,7 @@ public static String notBlank(String str, String message) {
* @return the supplied string
*/
public static String notBlank(String str, Supplier<String> messageSupplier) {
if (str == null || str.trim().isEmpty()) {
if (str == null || str.isBlank()) {
throw new PreconditionViolationException(messageSupplier.get());
}

Expand Down
12 changes: 5 additions & 7 deletions src/main/java/org/junitpioneer/internal/PioneerUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import org.junit.jupiter.api.extension.ExtensionContext;

Expand All @@ -40,7 +38,7 @@ private PioneerUtils() {
}

/**
* A {@link Collectors#toSet() toSet} collector that throws an {@link IllegalStateException}
* A {@link java.util.stream.Collectors#toSet() toSet} collector that throws an {@link IllegalStateException}
* on duplicate elements (according to {@link Object#equals(Object) equals}).
*/
public static <T> Collector<T, Set<T>, Set<T>> distinctToSet() {
Expand All @@ -63,7 +61,7 @@ private static <T> void addButThrowIfDuplicate(Set<T> set, T element) {
* interface and traversing its enclosing classes until such a method is
* found or the top level class is reached.
*
* <p>The algorithm does not search for methods in {@link java.lang.Object}.
* <p>The algorithm does not search for methods in {@link java.lang.Object}.</p>
*
* @param clazz the class or interface in which to find the method; never {@code null}
* @param methodName the name of the method to find; never {@code null} or empty
Expand All @@ -81,7 +79,7 @@ public static Optional<Method> findMethodCurrentOrEnclosing(Class<?> clazz, Stri
// null checking done by ReflectionSupport.findMethod
method = findMethod(current, methodName, parameterTypes);
current = current.getEnclosingClass();
} while (!method.isPresent() && current != null);
} while (method.isEmpty() && current != null);
return method;
}

Expand All @@ -98,7 +96,7 @@ public static List<ExtensionContext> findAllContexts(ExtensionContext context) {
List<ExtensionContext> parentContexts = context
.getParent()
.map(PioneerUtils::findAllContexts)
.orElse(Collections.emptyList());
.orElse(List.of());
allContexts.addAll(parentContexts);
return allContexts;
}
Expand Down Expand Up @@ -148,7 +146,7 @@ public static <T> Class<T> wrap(Class<T> clazz) {
public static List<List<?>> cartesianProduct(List<List<?>> lists) {
List<List<?>> resultLists = new ArrayList<>();
if (lists.isEmpty()) {
resultLists.add(Collections.emptyList());
resultLists.add(List.of());
return resultLists;
}
List<?> firstList = lists.get(0);
Expand Down
19 changes: 12 additions & 7 deletions src/main/java/org/junitpioneer/jupiter/DisableIfTestFails.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,23 @@

/**
* Disables all remaining tests in a container if one of them failed.
*
* <p>
Bukama marked this conversation as resolved.
Show resolved Hide resolved
* By default, all exceptions (including assertions, but exempting failed assumptions) will lead to
* disabling the remaining tests. To configure this in more detail, see {@link #with()} and
* {@link #onAssertion()}.
*
* </p>
* <p>
* This annotation can be (meta-)present on classes that contain a nested class. In that case, a
* failing test in the outer class will disable the nested class (if it runs later) and vice versa.
*
* </p>
* <p>
* This annotation can be (meta-)present on a class and/or its super types (classes or interfaces).
* In that case, the exception types given to {@link #with()} are merged and {@link #onAssertion()}
* is or'ed.
*
* </p>
* <p>
* But if a test fails in a specific class, only other tests in the corresponding container will
* be disabled. That means if...
* be disabled. That means if...</p>
*
* <ul>
* <li>a class {@code SpecificTests} implements interface {@code Tests} and</li>
Expand All @@ -52,19 +55,21 @@

/**
* Configure on which exceptions remaining tests are disabled (defaults to "any exception").
*
* <p>
* If {@code @DisableIfTestFails} is present multiple times (e.g. on multiple super types),
* these exceptions are collected across all annotations, meaning if any of the mentioned
* exceptions are thrown, the remaining tests are disabled.
* </p>
*/
Class<? extends Throwable>[] with() default {};

/**
* Set to {@code false} if failed assertions should not lead to disabling remaining tests.
*
* <p>
* If {@code @DisableIfTestFails} is present multiple times (e.g. on multiple super types),
* this value is or'ed, meaning as soon as one annotation says to fail on assertion errors,
* that's how the container will behave.
* </p>
*/
boolean onAssertion() default true;

Expand Down