/* * Copyright (c) 2012 - 2016 Jadler contributors * This program is made available under the terms of the MIT License. */ package net.jadler.stubbing; import net.jadler.Request; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import org.apache.commons.lang.Validate; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.StringDescription; import static org.hamcrest.Matchers.allOf; /** * <p>An http stub is a <em>WHEN</em>-<em>THEN</em> pair (when an http request with specific properties arrives, * then respond with a defined response).</p> * * <p>The <em>WHEN</em> part is a list of predicates (in form of Hamcrest matchers) applicable to a request. * All of these matchers must be evaluated to {@code true} in order to apply the <em>THEN</em> part.</p> * * <p>The <em>THEN</em> part is defined by an instance of the {@link Responder} interface. * This instance is capable of constructing stub http responses to be returned to the client.</p> * * <p>Instances of this class are thread-safe if and only if the provided {@link Responder} instance * is thread-safe.</p> * * <p>One should never create new instances of this class directly,see {@link net.jadler.Jadler} * for explanation and tutorial.</p> */ public class HttpStub { private final Collection<Matcher<? super Request>> predicates; private final Responder responder; /** * @param predicates list of predicates. Cannot be {@code null}, however can be empty (which means this rule will * match every request) * @param responder an instance to provide stub http responses */ public HttpStub(final Collection<Matcher<? super Request>> predicates, final Responder responder) { Validate.notNull(predicates, "predicates cannot be null, use an empty list instead"); this.predicates = new ArrayList<Matcher<? super Request>>(predicates); Validate.notNull(responder, "responder cannot be null"); this.responder = responder; } /** * @param request an http request to be checked whether it matches this stub rule. * @return {@code true} if and only if all predicates defined in this rule were evaluated to {@code true} * by the given request. */ public boolean matches(final Request request) { return allOf(this.predicates).matches(request); } /** * @param request an http request the stub response will be generated for * @return next http stub response as produced by the {@link Responder} instance provided in * {@link #HttpStub(java.util.Collection, net.jadler.stubbing.Responder)} */ public StubResponse nextResponse(final Request request) { return this.responder.nextResponse(request); } /** * Returns a reason why the given request doesn't match this rule. This method should be called if * and only if {@link #matches(net.jadler.Request)} would return {@code false}. However, this is not checked. * @param request an http request to describe the mismatch for * @return a human readable mismatch reason */ public String describeMismatch(final Request request) { final Description desc = new StringDescription(); boolean first = true; for (final Iterator<Matcher<? super Request>> it = this.predicates.iterator(); it.hasNext();) { final Matcher<? super Request> m = it.next(); if (!m.matches(request)) { if (!first) { desc.appendText(" AND\n"); } desc.appendText(" "); m.describeMismatch(request, desc); first = false; } } return desc.toString(); } @Override public String toString() { final Description desc = new StringDescription(); desc.appendText("WHEN request (\n"); for(final Iterator<Matcher<? super Request>> it = this.predicates.iterator(); it.hasNext();) { desc.appendText(" "); desc.appendDescriptionOf(it.next()); if (it.hasNext()) { desc.appendText(" AND\n"); } } desc.appendText(")\n"); desc.appendText("THEN respond with "); desc.appendText(this.responder.toString()); return desc.toString(); } }