package fr.sii.ogham.assertion; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.MatcherAssert; import org.hamcrest.StringDescription; import org.junit.ComparisonFailure; import fr.sii.ogham.assertion.hamcrest.CustomReason; import fr.sii.ogham.assertion.hamcrest.DecoratorMatcher; import fr.sii.ogham.assertion.hamcrest.ExpectedValueProvider; /** * Utility class for Ogham assertions. * * @author Aurélien Baudet * */ public class AssertionHelper { /** * Copy of {@link MatcherAssert#assertThat(Object, Matcher)} with the * following additions: * <ul> * <li>If the matcher can provide expected value, a * {@link ComparisonFailure} exception is thrown instead of * {@link AssertionError} in order to display differences between expected * string and actual string in the IDE.</li> * <li>If the matcher is a {@link CustomReason} matcher and no reason is * provided, the reason of the matcher is used to provide more information * about the context (which message has failed for example)</li> * </ul> * * @param actual * the actual value * @param matcher * the matcher to apply * @param <T> * the type used for the matcher */ public static <T> void assertThat(T actual, Matcher<? super T> matcher) { assertThat("", actual, matcher); } /** * Copy of {@link MatcherAssert#assertThat(String, Object, Matcher)} with * the following additions: * <ul> * <li>If the matcher can provide expected value, a * {@link ComparisonFailure} exception is thrown instead of * {@link AssertionError} in order to display differences between expected * string and actual string in the IDE.</li> * <li>If the matcher is a {@link CustomReason} matcher and no reason is * provided, the reason of the matcher is used to provide more information * about the context (which message has failed for example)</li> * </ul> * * @param reason * the reason * @param actual * the actual value * @param matcher * the matcher to apply * @param <T> * the type used for the matcher */ public static <T> void assertThat(String reason, T actual, Matcher<? super T> matcher) { if (!matcher.matches(actual)) { Description description = getDescription(reason, actual, matcher); if (hasExpectedValue(matcher)) { throw new ComparisonFailure(description.toString(), String.valueOf(getComparable(matcher).getExpectedValue()), String.valueOf(actual)); } else { throw new AssertionError(description.toString()); } } } @SuppressWarnings("unchecked") private static <T> boolean hasExpectedValue(Matcher<? super T> matcher) { if (matcher instanceof ExpectedValueProvider) { return true; } if (matcher instanceof DecoratorMatcher) { return hasExpectedValue(((DecoratorMatcher<T>) matcher).getDecoree()); } return false; } @SuppressWarnings("unchecked") private static <T> ExpectedValueProvider<T> getComparable(Matcher<? super T> matcher) { if (matcher instanceof ExpectedValueProvider) { return (ExpectedValueProvider<T>) matcher; } if (matcher instanceof DecoratorMatcher) { return getComparable(((DecoratorMatcher<T>) matcher).getDecoree()); } return null; } private static <T> Description getDescription(String reason, T actual, Matcher<? super T> matcher) { Description description = new StringDescription(); description.appendText(getReason(reason, matcher)).appendText("\nExpected: ").appendDescriptionOf(matcher).appendText("\n but: "); matcher.describeMismatch(actual, description); return description; } private static <T> String getReason(String reason, Matcher<? super T> matcher) { if (reason != null && !reason.isEmpty()) { return reason; } if (matcher instanceof CustomReason) { return ((CustomReason<?>) matcher).getReason(); } return ""; } private AssertionHelper() { super(); } }