package org.easyb.delegates;
import groovy.lang.Closure;
import org.easyb.exception.VerificationException;
import org.codehaus.groovy.runtime.InvokerInvocationException;
import java.util.ArrayList;
import java.util.List;
import java.io.Serializable;
/**
* The easy delegate handles "it", "then", and "when"
* Currently, this delegate isn't plug and play.
*
* @author aglover
*/
public class EnsuringDelegate implements Serializable{
/**
* @param clzz the class of the exception type expected
* @param closure closure containing code to be run that should throw an
* exception
*/
public void ensureThrows(final Class<?> clzz, final Closure closure) throws Exception {
List<Class<?>> clzzList = new ArrayList<Class<?>>() {{
add(clzz);
}};
ensureThrows(clzzList, closure);
}
/**
* @param clzzList a list of classes of the possible exception types
* @param closure closure containing code to be run that should throw an
* exception
*/
public void ensureThrows(final List<Class<?>> clzzList, final Closure closure) throws Exception {
try {
closure.call();
} catch (Throwable e) {
boolean caught = false;
for (Class<?> clzz : clzzList) {
if (clzz.isAssignableFrom(e.getClass()) || (e.getCause() != null
&& e.getCause().getClass() == clzz)) {
caught = true;
break;
}
}
if (!caught) {
throw new VerificationException(
"exception caught (" + e.getClass().getName() + ") is not of type " + clzzList +
" or the cause isn't " + clzzList);
}
return;
}
throw new VerificationException("expected exception of type " + clzzList + " was not thrown");
}
/**
* @param clzz the class of the exception type expected
* @param closure closure containing code to be run that should throw an
* exception
*/
public void ensureStrictThrows(final Class<?> clzz, final Closure closure) throws Exception {
List<Class<?>> clzzList = new ArrayList<Class<?>>() {{
add(clzz);
}};
ensureStrictThrows(clzzList, closure);
}
/**
* @param clzzList a list of classes of the possible exception types
* @param closure closure containing code to be run that should throw an
* exception
*/
public void ensureStrictThrows(final List<Class<?>> clzzList, final Closure closure) throws Exception {
try {
closure.call();
} catch (Throwable e) {
boolean caught = false;
for (Class<?> clzz : clzzList) {
if (clzz == e.getClass() || (e.getCause() != null
&& e.getCause().getClass() == clzz)) {
caught = true;
break;
}
}
if (!caught) {
throw new VerificationException(
e.getClass().getName() + " was caught. The cause was "
+ getCauseClause(e)
+ " not "
+ clzzList
+ " as specified.");
}
return;
}
throw new VerificationException("expected exception of type " + clzzList + " was not thrown");
}
private String getCauseClause(Throwable e) {
if(e.getCause() != null){
return e.getCause().getClass().toString();
}else{
return "undetermined";
}
}
/**
* @param expression to be evaluated and should resolve to a boolean result
*/
public void ensure(final boolean expression) throws Exception {
if (!expression) {
throw new VerificationException("the expression evaluated to false");
}
}
/**
*
* @param timeout
* @param closure
*/
public void ensureUntil(final int timeout, final Closure closure) {
long starttime = System.currentTimeMillis();
long currtime = starttime;
Throwable storedEx = null;
while (currtime < starttime + timeout * 1000) {
try {
closure.call();
return;
} catch (InvokerInvocationException e) {
if (e.getCause().getClass().equals(VerificationException.class)) {
storedEx = e;
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
}
}
currtime = System.currentTimeMillis();
}
if (storedEx != null) {
throw new VerificationException(storedEx.getCause().getMessage() +
" (Tried repeatedly for " + timeout + " seconds)");
} else {
throw new VerificationException("Failed even after waiting "
+ timeout + " seconds");
}
}
/**
* @param value
* @param closure
* @throws Exception
*/
public void ensure(final Object value, final Closure closure)
throws Exception {
RichlyEnsurable delegate = this.getDelegate(value);
closure.setDelegate(delegate);
closure.call();
}
/**
* @param closure closure containing code to be run that should throw a VerificationException
*/
public void ensureFails(Closure closure) throws Exception {
ensureThrows(VerificationException.class, closure);
}
/**
* @return FlexibleDelegate instance
*/
private RichlyEnsurable getDelegate(final Object value) throws Exception {
RichlyEnsurable delegate = EnsurableFactory.manufacture();
delegate.setVerified(value);
return delegate;
}
/**
* @param message
*/
public void fail(String message) {
throw new VerificationException(message);
}
/**
* @param message
* @param e
*/
public void fail(String message, Exception e) {
throw new VerificationException(message, e);
}
/**
* @param message
* @param expected
* @param actual
*/
public void fail(String message, Object expected, Object actual) {
throw new VerificationException(message, expected, actual);
}
}