Source: InvocationExpectation.java
package org.jmock.internal;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.core.IsAnything;
import org.jmock.api.Action;
import org.jmock.api.Expectation;
import org.jmock.api.Invocation;
import org.jmock.api.Invocation.ExpectationMode;
import org.jmock.internal.matcher.MethodMatcher;
import org.jmock.lib.action.VoidAction;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* An expectation of zero or more matching invocations.
*
* @author npryce
* @author smgf
*/
public class InvocationExpectation implements Expectation {
private static ParametersMatcher ANY_PARAMETERS = new AnyParametersMatcher();
private Cardinality cardinality = Cardinality.ALLOWING;
private Matcher<?> objectMatcher = IsAnything.anything();
private Matcher<? super Method> methodMatcher = IsAnything.anything("<any method>");
private boolean methodIsKnownToBeVoid = false;
private ParametersMatcher parametersMatcher = ANY_PARAMETERS;
private Action action = new VoidAction();
private boolean actionIsDefault = true;
private List<OrderingConstraint> orderingConstraints = new ArrayList<OrderingConstraint>();
private List<SideEffect> sideEffects = new ArrayList<SideEffect>();
private int invocationCount = 0;
public void setCardinality(Cardinality cardinality) {
this.cardinality = cardinality;
}
public void setObjectMatcher(Matcher<?> objectMatcher) {
this.objectMatcher = objectMatcher;
}
public void setMethod(Method method) {
this.methodMatcher = new MethodMatcher(method);
this.methodIsKnownToBeVoid = method.getReturnType() == void.class;
}
public void setMethodMatcher(Matcher<? super Method> matcher) {
this.methodMatcher = matcher;
this.methodIsKnownToBeVoid = false;
}
public void setParametersMatcher(ParametersMatcher parametersMatcher) {
this.parametersMatcher = parametersMatcher;
}
public void addOrderingConstraint(OrderingConstraint orderingConstraint) {
orderingConstraints.add(orderingConstraint);
}
public void addSideEffect(SideEffect sideEffect) {
sideEffects.add(sideEffect);
}
public void setAction(Action action) {
this.action = action;
this.actionIsDefault = false;
}
public void setDefaultAction(Action action) {
this.action = action;
this.actionIsDefault = true;
}
public void describeTo(Description description) {
if (! isSatisfied()) {
description.appendText("! ");
}
describeExpectation(description);
}
public void describeMismatch(Invocation invocation, Description description) {
describeExpectation(description);
final Object[] parameters = invocation.getParametersAsArray();
if (methodMatcher.matches(invocation.getInvokedMethod()) &&
parametersMatcher.isCompatibleWith(parameters))
{
parametersMatcher.describeMismatch(parameters, description);
}
}
private void describeExpectation(Description description) {
describeMethod(description);
parametersMatcher.describeTo(description);
describeSideEffects(description);
}
private void describeMethod(Description description) {
cardinality.describeTo(description);
description.appendText(", ");
if (invocationCount == 0) {
description.appendText("never invoked");
}
else {
description.appendText("already invoked ");
description.appendText(Formatting.times(invocationCount));
}
description.appendText(": ");
objectMatcher.describeTo(description);
description.appendText(".");
methodMatcher.describeTo(description);
}
private void describeSideEffects(Description description) {
for (OrderingConstraint orderingConstraint : orderingConstraints) {
description.appendText("; ");
orderingConstraint.describeTo(description);
}
if (!shouldSuppressActionDescription()) {
description.appendText("; ");
action.describeTo(description);
}
for (SideEffect sideEffect : sideEffects) {
description.appendText("; ");
sideEffect.describeTo(description);
}
}
private boolean shouldSuppressActionDescription() {
return methodIsKnownToBeVoid && actionIsDefault;
}
public boolean isSatisfied() {
return cardinality.isSatisfied(invocationCount);
}
public boolean allowsMoreInvocations() {
return cardinality.allowsMoreInvocations(invocationCount);
}
public boolean matches(Invocation invocation) {
return allowsMoreInvocations()
&& objectMatcher.matches(invocation.getInvokedObject())
&& methodMatcher.matches(invocation.getInvokedMethod())
&& parametersMatcher.matches(invocation.getParametersAsArray())
&& isInCorrectOrder();
}
private boolean isInCorrectOrder() {
for (OrderingConstraint constraint : orderingConstraints) {
if (!constraint.allowsInvocationNow()) return false;
}
return true;
}
public Object invoke(Invocation invocation) throws Throwable {
invocationCount++;
performSideEffects();
final Object result = action.invoke(new Invocation(ExpectationMode.ASSERTING, invocation));
invocation.checkReturnTypeCompatibility(result);
return result;
}
private void performSideEffects() {
for (SideEffect sideEffect : sideEffects) {
sideEffect.perform();
}
}
private static class AnyParametersMatcher extends IsAnything<Object[]> implements ParametersMatcher {
public AnyParametersMatcher() {
super("(<any parameters>)");
}
public boolean isCompatibleWith(Object[] parameters) {
return true;
}
};
}