/*
* Created on May 21, 2007
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright @2007-2013 the original author or authors.
*/
package org.fest.assertions;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collection;
import static org.fest.assertions.ErrorMessages.unexpectedIn;
import static org.fest.assertions.ErrorMessages.unexpectedNotIn;
import static org.fest.assertions.Fail.*;
import static org.fest.assertions.Formatting.format;
import static org.fest.util.Lists.newArrayList;
import static org.fest.util.Objects.areEqual;
import static org.fest.util.Preconditions.checkNotNull;
/**
* Template for assertions.
*
* @param <S> used to simulate "self types." For more information please read "<a href="http://goo.gl/fjgOM"
* target="_blank">Emulating 'self types' using Java Generics to simplify fluent API
* implementation</a>."
* @param <A> the type the "actual" value.
* @author Yvonne Wang
* @author Alex Ruiz
*/
public abstract class GenericAssert<S, A> extends Assert {
protected final A actual;
protected final S myself;
/**
* Creates a new {@link GenericAssert}.
*
* @param selfType the "self type."
* @param actual the actual value to verify.
*/
protected GenericAssert(@Nonnull Class<S> selfType, @Nullable A actual) {
this.actual = actual;
myself = selfType.cast(this);
}
/**
* Asserts that the actual value (specified in the constructor of this class) is {@code null}.
*
* @throws AssertionError if the actual value is not {@code null}.
*/
public final void isNull() {
failIfNotNull(customErrorMessage(), rawDescription(), actual);
}
/**
* Verifies that the actual value satisfies the given condition.
*
* @param condition the given condition.
* @return this assertion object.
* @throws NullPointerException if the given condition is {@code null}.
* @throws AssertionError if the actual value does not satisfy the given condition.
* @see #is(Condition)
*/
public final @Nonnull S satisfies(@Nonnull Condition<A> condition) {
if (matches(condition)) {
return myself();
}
failIfCustomMessageIsSet();
throw failure(errorMessageIfConditionNotSatisfied(condition));
}
private @Nonnull String errorMessageIfConditionNotSatisfied(@Nonnull Condition<A> condition) {
return condition.addDescriptionTo(format("actual value:<%s> should satisfy condition", actual));
}
/**
* Verifies that the actual value does not satisfy the given condition.
*
* @param condition the given condition.
* @return this assertion object.
* @throws NullPointerException if the given condition is {@code null}.
* @throws AssertionError if the actual value satisfies the given condition.
* @see #isNot(Condition)
*/
public final @Nonnull S doesNotSatisfy(@Nonnull Condition<A> condition) {
if (!matches(condition)) {
return myself();
}
failIfCustomMessageIsSet();
throw failure(errorMessageIfConditionSatisfied(condition));
}
private @Nonnull String errorMessageIfConditionSatisfied(@Nonnull Condition<A> condition) {
return condition.addDescriptionTo(format("actual value:<%s> should not satisfy condition", actual));
}
/**
* Alias for {@link #satisfies(Condition)}.
*
* @param condition the given condition.
* @return this assertion object.
* @throws NullPointerException if the given condition is {@code null}.
* @throws AssertionError if the actual value does not satisfy the given condition.
* @since 1.2
*/
public final @Nonnull S is(@Nonnull Condition<A> condition) {
if (matches(condition)) {
return myself();
}
failIfCustomMessageIsSet();
throw failure(errorMessageIfIsNot(condition));
}
private @Nonnull String errorMessageIfIsNot(@Nonnull Condition<A> condition) {
return condition.addDescriptionTo(format("actual value:<%s> should be", actual));
}
/**
* Alias for {@link #doesNotSatisfy(Condition)}.
*
* @param condition the given condition.
* @return this assertion object.
* @throws NullPointerException if the given condition is {@code null}.
* @throws AssertionError if the actual value satisfies the given condition.
* @since 1.2
*/
public final @Nonnull S isNot(@Nonnull Condition<A> condition) {
if (!matches(condition)) {
return myself();
}
failIfCustomMessageIsSet();
throw failure(errorMessageIfIs(condition));
}
private boolean matches(@Nonnull Condition<A> condition) {
checkNotNull(condition);
return condition.matches(actual);
}
private @Nonnull String errorMessageIfIs(@Nonnull Condition<A> condition) {
return condition.addDescriptionTo(format("actual value:<%s> should not be", actual));
}
/**
* Sets the description of the actual value, to be used in as message of any {@code AssertionError} thrown when an
* assertion fails. This method should be called before any assertion method, otherwise any assertion failure will not
* show the provided description.
* <p/>
* For example:
* <pre>
* assertThat(val).<strong>as</strong>("name").isEqualTo("Frodo");
* </pre>
*
* @param description the description of the actual value.
* @return this assertion object.
*/
public @Nonnull S as(@Nullable String description) {
description(description);
return myself();
}
/**
* Alias for {@link #as(String)}, since "as" is a keyword in <a href="http://groovy.codehaus.org/"
* target="_blank">Groovy</a>. This method should be called before any assertion method, otherwise any assertion
* failure will not show the provided description.
* <p/>
* For example:
* <pre>
* assertThat(val).<strong>describedAs</strong>("name").isEqualTo("Frodo");
* </pre>
*
* @param description the description of the actual value.
* @return this assertion object.
*/
public @Nonnull S describedAs(@Nullable String description) {
return as(description);
}
/**
* Sets the description of the actual value, to be used in as message of any {@code AssertionError} thrown when an
* assertion fails. This method should be called before any assertion method, otherwise any assertion failure will not
* show the provided description.
* <p/>
* For example:
* <pre>
* assertThat(val).<strong>as</strong>(new BasicDescription("name")).isEqualTo("Frodo");
* </pre>
*
* @param description the description of the actual value.
* @return this assertion object.
*/
public @Nonnull S as(@Nullable Description description) {
description(description);
return myself();
}
/**
* Alias for {@link #as(Description)}, since "as" is a keyword in <a href="http://groovy.codehaus.org/"
* target="_blank">Groovy</a>. This method should be called before any assertion method, otherwise any assertion
* failure will not show the provided description.
* <p/>
* For example:
* <pre>
* assertThat(val).<strong>describedAs</strong>(new BasicDescription("name")).isEqualTo("Frodo");
* </pre>
*
* @param description the description of the actual value.
* @return this assertion object.
*/
public @Nonnull S describedAs(@Nullable Description description) {
return as(description);
}
/**
* Verifies that the actual value is equal to the given one.
*
* @param expected the given value to compare the actual value to.
* @return this assertion object.
* @throws AssertionError if the actual value is not equal to the given one.
*/
public @Nonnull S isEqualTo(@Nullable A expected) {
failIfNotEqual(customErrorMessage(), rawDescription(), actual, expected);
return myself();
}
/**
* Verifies that the actual value is not equal to the given one.
*
* @param other the given value to compare the actual value to.
* @return this assertion object.
* @throws AssertionError if the actual value is equal to the given one.
*/
public @Nonnull S isNotEqualTo(@Nullable A other) {
failIfEqual(customErrorMessage(), rawDescription(), actual, other);
return myself();
}
/**
* Verifies that the actual value is not {@code null}.
*
* @return this assertion object.
* @throws AssertionError if the actual value is {@code null}.
*/
public final @Nonnull S isNotNull() {
failIfActualIsNull(customErrorMessage(), rawDescription(), actual);
return myself();
}
/**
* Verifies that the actual value is the same as the given one.
*
* @param expected the given value to compare the actual value to.
* @return this assertion object.
* @throws AssertionError if the actual value is not the same as the given one.
*/
public final @Nonnull S isSameAs(@Nullable A expected) {
failIfNotSame(customErrorMessage(), rawDescription(), actual, expected);
return myself();
}
/**
* Verifies that the actual value is not the same as the given one.
*
* @param other the given value to compare the actual value to.
* @return this assertion object.
* @throws AssertionError if the actual value is the same as the given one.
*/
public final @Nonnull S isNotSameAs(@Nullable A other) {
failIfSame(customErrorMessage(), rawDescription(), actual, other);
return myself();
}
/**
* Verifies that the actual value is in the given values.
*
* @param values the given values to search the actual value in.
* @return this assertion object.
* @throws AssertionError if the actual value is not in the given values.
* @throws NullPointerException if the given parameter is null.
*/
public final @Nonnull S isIn(@Nonnull Object... values) {
return isIn(newArrayList(values));
}
/**
* Verifies that the actual value is in the given collection.
*
* @param values the given collection to search the actual value in. must not be null.
* @return this assertion object.
* @throws AssertionError if the actual value is not in the given collection.
* @throws NullPointerException if the given collection is null.
*/
public final @Nonnull S isIn(@Nonnull Collection<?> values) {
checkNotNull(values);
if (isActualIn(values)) {
return myself();
}
failIfCustomMessageIsSet();
throw failure(unexpectedNotIn(actual, values));
}
/**
* Verifies that the actual value is in the given values.
*
* @param values the given values to search the actual value in.
* @return this assertion object.
* @throws AssertionError if the actual value is not in the given values.
* @throws NullPointerException if the given parameter is null.
*/
public final @Nonnull S isNotIn(@Nonnull Object... values) {
return isNotIn(newArrayList(values));
}
/**
* Verifies that the actual value is in the given collection.
*
* @param values the given collection to search the actual value in. must not be null.
* @return this assertion object.
* @throws AssertionError if the actual value is not in the given collection.
* @throws NullPointerException if the given collection is null.
*/
public final @Nonnull S isNotIn(@Nonnull Collection<?> values) {
checkNotNull(values);
if (!isActualIn(values)) {
return myself();
}
failIfCustomMessageIsSet();
throw failure(unexpectedIn(actual, values));
}
private boolean isActualIn(@Nonnull Collection<?> values) {
if (values.isEmpty()) {
return false;
}
for (Object value : values) {
if (areEqual(actual, value)) {
return true;
}
}
return false;
}
/**
* Replaces the default message displayed in case of a failure with the given one.
* <p/>
* For example, the following assertion:
* <pre>
* assertThat("Hello").isEqualTo("Bye");
* </pre>
* will fail with the default message "<em>expected:<'[Bye]'> but was:<'[Hello]'></em>."
* <p/>
* We can replace this message with our own:
* <pre>
* assertThat("Hello").overridingErrorMessage("'Hello' should be equal to 'Bye'").isEqualTo("Bye");
* </pre>
* in this case, the assertion will fail showing the message "<em>'Hello' should be equal to 'Bye'</em>".
*
* @param message the given error message, which will replace the default one.
* @return this assertion.
* @since 1.2
*/
public @Nonnull S overridingErrorMessage(@Nullable String message) {
replaceDefaultErrorMessagesWith(message);
return myself();
}
protected final @Nonnull S myself() {
return checkNotNull(myself);
}
}