edu.hm.hafner.util.Ensure Maven / Gradle / Ivy
package edu.hm.hafner.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Formatter;
import java.util.List;
import com.google.errorprone.annotations.FormatMethod;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.CheckReturnValue;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Provides several helper methods to validate method arguments and class invariants, thus supporting the design by
* contract concept (DBC).
*
*
* Note: the static methods provided by this class use a fluent interface, i.e., in order to verify an assertion a
* method sequence needs to be called.
*
*
* Available checks:
*
*
* - Boolean assertions, e.g., {@code Ensure.that(condition).isTrue(); }
* - String assertions, e.g., {@code Ensure.that(string).isNotEmpty(); }
* - Object assertions, e.g., {@code Ensure.that(element).isNotNull(); }
* - Array assertions, e.g., {@code Ensure.that(array).isNotEmpty(); }
* - Iterable assertions, e.g., {@code Ensure.that(collection).isNotNull(); }
*
*
* @author Ullrich Hafner
* @see Design by Contract (Meyer, Bertrand)
*/
public final class Ensure {
/**
* Returns a boolean condition.
*
* @param value
* the value to check
*
* @return a boolean condition
*/
@CheckReturnValue
public static BooleanCondition that(final boolean value) {
return new BooleanCondition(value);
}
/**
* Returns an object condition.
*
* @param value
* the value to check
* @param additionalValues
* the additional values to check
* @param
* type to check
*
* @return an object condition
*/
@CheckReturnValue
public static ObjectCondition that(@CheckForNull final T value,
@CheckForNull final Object... additionalValues) {
return new ObjectCondition<>(value, additionalValues);
}
/**
* Returns an iterable condition.
*
* @param value
* the value to check
*
* @return an iterable condition
*/
@CheckReturnValue
public static IterableCondition that(@CheckForNull final Iterable value) {
return new IterableCondition(value);
}
/**
* Returns a collection condition.
*
* @param value
* the value to check
*
* @return a collection condition
*/
@CheckReturnValue
public static CollectionCondition that(@CheckForNull final Collection value) {
return new CollectionCondition(value);
}
/**
* Returns an array condition.
*
* @param value
* the value to check
*
* @return an array condition
*/
@SuppressWarnings({"PMD.UseVarargs", "AvoidObjectArrays"})
@CheckReturnValue
public static ArrayCondition that(@CheckForNull final Object[] value) {
return new ArrayCondition(value);
}
/**
* Returns a string condition.
*
* @param value
* the value to check
*
* @return a string condition
*/
@CheckReturnValue
public static StringCondition that(@CheckForNull final String value) {
return new StringCondition(value);
}
/**
* Returns an exception condition.
*
* @param value
* the value to check
*
* @return an exception condition
*/
@CheckReturnValue
public static ExceptionCondition that(@CheckForNull final Throwable value) {
return new ExceptionCondition(value);
}
/**
* Always throws an {@link AssertionError}.
*/
public static void thatStatementIsNeverReached() {
throwException("This statement should never be reached.");
}
/**
* Always throws an {@link AssertionError}.
*
* @param explanation
* a {@link Formatter formatted message} explaining the assertion
* @param args
* Arguments referenced by the format specifiers in the formatted explanation. If there are more arguments
* than format specifiers, the extra arguments are ignored. The number of arguments is variable and may be
* zero.
*/
@FormatMethod
public static void thatStatementIsNeverReached(final String explanation, final Object... args) {
throwException(explanation, args);
}
/**
* Throws an {@link AssertionError} with the specified detail message.
*
* @param message
* a {@link Formatter formatted message} with the description of the error
* @param args
* Arguments referenced by the format specifiers in the formatted message. If there are more arguments than
* format specifiers, the extra arguments are ignored. The number of arguments is variable and may be zero.
*
* @throws AssertionError
* always thrown
*/
@FormatMethod
private static void throwException(final String message, @CheckForNull final Object... args) {
throw new AssertionError(String.format(message, args));
}
/**
* Throws a {@link NullPointerException} with the specified detail message.
*
* @param message
* a {@link Formatter formatted message} with the description of the error
* @param args
* Arguments referenced by the format specifiers in the formatted message. If there are more arguments than
* format specifiers, the extra arguments are ignored. The number of arguments is variable and may be zero.
*
* @throws AssertionError
* always thrown
*/
@FormatMethod
private static void throwNullPointerException(final String message, final Object... args) {
throw new NullPointerException(String.format(message, args)); // NOPMD
}
private Ensure() {
// prevents instantiation
}
/**
* Assertions for iterables.
*/
public static class IterableCondition extends ObjectCondition> {
/**
* Creates a new instance of {@code IterableCondition}.
*
* @param value
* value of the condition
*/
public IterableCondition(@CheckForNull final Iterable value) {
super(value);
}
/**
* Ensures that the given iterable is not {@code null} and contains at least one element. Additionally, ensures
* that each element of the iterable is not {@code null}.
*
* @throws AssertionError
* if the iterable is empty (or {@code null}), or at least one iterable element is {@code null}.
*/
public void isNotEmpty() {
isNotEmpty("Iterable is empty or NULL");
}
/**
* Ensures that the given iterable is not {@code null} and contains at least one element. Additionally, ensures
* that each element of the iterable is not {@code null}.
*
* @param explanation
* a {@link Formatter formatted message} explaining the assertion
* @param args
* Arguments referenced by the format specifiers in the formatted explanation. If there are more
* arguments than format specifiers, the extra arguments are ignored. The number of arguments is
* variable and may be zero.
*
* @throws AssertionError
* if the iterable is empty (or {@code null}), or at least one iterable element is {@code null}.
*/
@FormatMethod
public void isNotEmpty(final String explanation, final Object... args) {
isNotNull(explanation, args);
if (getValue().iterator().hasNext()) {
for (Object object : getValue()) {
if (object == null) {
throwException(explanation, args);
}
}
}
else {
throwException(explanation, args);
}
}
}
/**
* Assertions for iterables.
*/
public static class CollectionCondition extends IterableCondition {
/**
* Creates a new instance of {@code CollectionCondition}.
*
* @param value
* value of the condition
*/
public CollectionCondition(@CheckForNull final Collection value) {
super(value);
}
@Override
Collection getValue() {
return (Collection) super.getValue();
}
/**
* Ensures that the given collection is not {@code null} and contains the specified element.
*
* @param element
* the element to find
*
* @throws AssertionError
* if the collection is {@code null} or if the specified element is not found
*/
public void contains(final Object element) {
contains(element, "Collection %s does not contain element '%s'", getValue(), element);
}
/**
* Ensures that the given collection is not {@code null} and contains the specified element.
*
* @param element
* the element to find
* @param explanation
* a {@link Formatter formatted message} explaining the assertion
* @param args
* Arguments referenced by the format specifiers in the formatted explanation. If there are more
* arguments than format specifiers, the extra arguments are ignored. The number of arguments is
* variable and may be zero.
*
* @throws AssertionError
* if the collection is {@code null} or if the specified element is not found
*/
@FormatMethod
public void contains(final Object element, final String explanation, final Object... args) {
isNotNull(explanation, args);
if (!getValue().contains(element)) {
throwException(explanation, args);
}
}
/**
* Ensures that the given collection is not {@code null} and does not contain the specified element.
*
* @param element
* the element that must not be in the collection
*
* @throws AssertionError
* if the collection is {@code null} or if the specified element is part of the collection
*/
public void doesNotContain(final Object element) {
doesNotContain(element, "Collection '%s' contains element '%s'", getValue(), element);
}
/**
* Ensures that the given collection is not {@code null} and does not contain the specified element.
*
* @param element
* the element that must not be in the collection
* @param explanation
* a {@link Formatter formatted message} explaining the assertion
* @param args
* Arguments referenced by the format specifiers in the formatted explanation. If there are more
* arguments than format specifiers, the extra arguments are ignored. The number of arguments is
* variable and may be zero.
*
* @throws AssertionError
* if the collection is {@code null} or if the specified element is part of the collection
*/
@FormatMethod
public void doesNotContain(final Object element, final String explanation, final Object... args) {
isNotNull(explanation, args);
if (getValue().contains(element)) {
throwException(explanation, args);
}
}
}
/**
* Assertions for arrays.
*/
public static class ArrayCondition extends ObjectCondition