/*
* Copyright (c) 2012 - 2016 Jadler contributors
* This program is made available under the terms of the MIT License.
*/
package net.jadler.matchers;
import net.jadler.exception.JadlerException;
import net.jadler.Request;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import static org.apache.commons.lang.Validate.notNull;
/**
* Convenient base class for all Jadler request matchers.
* @param <T> type of the value retrieved from the given request to be matched
*/
public abstract class RequestMatcher<T> extends BaseMatcher<Request> {
protected final Matcher<? super T> pred;
/**
* @param pred predicate to be applied on the value retrieved from the given request (cannot be {@code null})
*/
protected RequestMatcher(final Matcher<? super T> pred) {
notNull(pred, "pred cannot be null");
this.pred = pred;
}
/**
* {@inheritDoc}
*/
@Override
public void describeMismatch(final Object item, final Description description) {
final T value;
try {
value = this.retrieveValue((Request) item);
} catch (Exception ex) {
throw new JadlerException("An error occurred while retrieving a value from the http request "
+ "for mismatch description", ex);
}
description.appendText("REQUIRED: ");
description.appendDescriptionOf(this);
description.appendText(" BUT ");
this.pred.describeMismatch(value, description);
}
/**
* {@inheritDoc}
*/
@Override
public void describeTo(final Description description) {
description.appendText(this.provideDescription());
description.appendText(" ");
description.appendDescriptionOf(this.pred);
}
/**
* Checks whether the given {@link Request} object matches this matcher.
* @param o {@link Request} object to be matched by this matcher. If this param is not of type {@link Request} this
* method will always return {@code false}.
* @return {@code true} if the value retrieved using {@link #retrieveValue(net.jadler.Request)} from the given
* {@link Request} object matches the predicate registered by the {@link #RequestMatcher(org.hamcrest.Matcher)},
* otherwise {@code false}.
*/
@Override
public boolean matches(final Object o) {
if (!(o instanceof Request)) {
return false;
}
T value;
try {
value = this.retrieveValue((Request) o);
}
catch (final Exception e) {
throw new JadlerException("An error occurred while retrieving a value from the http request", e);
}
return this.pred.matches(value);
}
/**
* Reads a value of the given request object (the value can be anything retrievable from the request
* object: method, header, body,...).
* @param req request object to read a value from
* @return a value retrieved from the given request object.
* @throws Exception when something goes wrong. This exception will be handler correctly by Jadler.
*/
protected abstract T retrieveValue(final Request req) throws Exception;
/**
* <p>Provides a description of this matcher in form of a string consisting of "<em>noun</em> <em>verb</em>", where
* noun describes the value retrieved using {@link #retrieveValue(net.jadler.Request)} and verb is usually a correct
* form of <em>to be</em>.</p>
*
* <p>If the {@link #retrieveValue(net.jadler.Request)} provided a request method, this method would return
* <em>method is</em> string for example.</p>
* @return matcher description
*/
protected abstract String provideDescription();
}