Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

PoC of ConditionFactory for FEST-Assert

View FestConditionFactory.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
package com.jayway.awaitility.core;
 
import com.jayway.awaitility.Duration;
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import org.fest.assertions.api.BigDecimalAssert;
import org.fest.assertions.api.IntegerAssert;
import org.fest.assertions.api.ListAssert;
import org.fest.assertions.core.Assert;
 
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.Callable;
 
import static java.lang.String.format;
import static org.fest.assertions.api.Assertions.assertThat;
 
public class FestConditionFactory extends ConditionFactory {
public FestConditionFactory(String alias, Duration timeout, Duration pollInterval, Duration pollDelay,
boolean catchUncaughtExceptions) {
super(alias, timeout, pollInterval, pollDelay, catchUncaughtExceptions);
}
 
public FestConditionFactory(Duration timeout, Duration pollInterval, Duration pollDelay,
boolean catchUncaughtExceptions) {
super(timeout, pollInterval, pollDelay, catchUncaughtExceptions);
}
 
public IntegerAssert untilCallFest2(Integer ignored) throws Exception {
final MethodCaller<Integer> valueSupplier = new MethodCaller<Integer>(MethodCallRecorder.getLastTarget(), MethodCallRecorder
.getLastMethod(), MethodCallRecorder.getLastArgs());
MethodCallRecorder.reset();
 
return createTypedProxy(new IntegerAssertThatSupplier(valueSupplier), generateConditionSettings(), IntegerAssert.class, Integer.class);
}
 
public BigDecimalAssert untilCallFest(BigDecimal ignored) throws Exception {
//TODO: MZA: Duplicated, can be moved inside some method
final MethodCaller<BigDecimal> valueSupplier = new MethodCaller<BigDecimal>(MethodCallRecorder.getLastTarget(), MethodCallRecorder
.getLastMethod(), MethodCallRecorder.getLastArgs());
MethodCallRecorder.reset();
 
return createTypedProxy(new BigDecimalAssertThatSupplier(valueSupplier), generateConditionSettings(), BigDecimalAssert.class, BigDecimal.class);
}
 
public <T> ListAssert<T> untilCallFest(List<T> ignored) throws Exception {
final MethodCaller<List<T>> valueSupplier = new MethodCaller<List<T>>(MethodCallRecorder.getLastTarget(), MethodCallRecorder
.getLastMethod(), MethodCallRecorder.getLastArgs());
MethodCallRecorder.reset();
 
return createTypedProxy(new ListAssertThatSupplier<T>(valueSupplier), generateConditionSettings(), ListAssert.class, List.class);
}
 
private <T, TA extends Assert<TA, T>> TA createTypedProxy(final Callable<TA> assertThatSupplier, final ConditionSettings settings, Class assertionClass, Class valueClass) {
try {
ProxyFactory pf = new ProxyFactory();
pf.setSuperclass(assertionClass);
pf.setFilter(new MethodFilter() {
public boolean isHandled(Method method) {
System.out.println(method.toString() + " " + method.getModifiers() + " " + Modifier.isFinal(method.getModifiers()));
return true; //TODO: MZA: something to ignore?
}
});
//TODO: MZA: Only the first "real" method from *Assert will be proxied. Can we ensure that this is
// an intended method (not some util method like as())?
MethodHandler handler = new MethodHandler() {
public Object invoke(final Object self, final Method thisMethod, final Method proceed, final Object[] args) throws Throwable {
System.out.println(format("Method %s called: ", thisMethod.getName()));
 
Callable<TA> delegate = new Callable<TA>() {
public TA call() throws Exception {
TA realAssert = assertThatSupplier.call();
return (TA)thisMethod.invoke(realAssert, args);
}
};
 
FestTypedCondition<T, TA> festCondition = new FestTypedCondition<T, TA>(delegate, settings);
festCondition.await();
//TODO: MZA: Temporarily assumption that assert methods are always void methods
return null;
}
};
 
//TODO: MZA: Will null work with every assert? Maybe there is an easier way to create mock on some class?
// we don't need the real object below - it is created internally during invocation
TA proxy = (TA) pf.create(new Class[]{valueClass}, new Object[]{null}, handler);
return proxy;
 
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
 
class FestTypedCondition<T, TA extends Assert<TA, T>> implements Condition {
 
private ConditionAwaiter conditionAwaiter;
 
FestTypedCondition(final Callable<TA> assertionSupplier, ConditionSettings settings) {
final Callable<Boolean> callable = new Callable<Boolean>() {
public Boolean call() throws Exception {
try {
assertionSupplier.call();
return true;
} catch (InvocationTargetException e) {
if (e.getCause() instanceof AssertionError) {
System.out.printf("AssertionError: %s, %s\n", e.getCause().getMessage(), e.getCause().getClass());
return false;
} else {
throw e;
}
}
}
};
 
conditionAwaiter = new ConditionAwaiter(callable, settings) {
@Override
protected String getTimeoutMessage() {
//TODO: MZA: Remember the last error message from AssertionError (as a field) and use it here
return String.format("%s expected %s but was <%s>", "Ups"/*getCallableDescription(assertionSupplier)*/, "Ups2"/*HamcrestToStringFilter.filter(matcher)*/, "TODO result");
}
};
}
 
public void await() throws Exception {
conditionAwaiter.await();
}
}
}
 
abstract class AbstractAssertThatSupplier<T, AT> implements Callable<AT> {
private final ConditionFactory.MethodCaller<T> valueSupplier;
 
protected AbstractAssertThatSupplier(ConditionFactory.MethodCaller<T> valueSupplier) {
this.valueSupplier = valueSupplier;
}
 
protected T getValueFromSupplier() throws Exception {
return valueSupplier.call();
}
}
 
class BigDecimalAssertThatSupplier extends AbstractAssertThatSupplier<BigDecimal, BigDecimalAssert> {
BigDecimalAssertThatSupplier(ConditionFactory.MethodCaller<BigDecimal> valueSupplier) {
super(valueSupplier);
}
 
public BigDecimalAssert call() throws Exception {
return assertThat(getValueFromSupplier());
}
}
class IntegerAssertThatSupplier extends AbstractAssertThatSupplier<Integer, IntegerAssert> {
IntegerAssertThatSupplier(ConditionFactory.MethodCaller<Integer> valueSupplier) {
super(valueSupplier);
}
 
public IntegerAssert call() throws Exception {
return assertThat(getValueFromSupplier());
}
}
 
class ListAssertThatSupplier<T> extends AbstractAssertThatSupplier<List<T>, ListAssert<T>> {
ListAssertThatSupplier(ConditionFactory.MethodCaller<List<T>> valueSupplier) {
super(valueSupplier);
}
 
public ListAssert<T> call() throws Exception {
return assertThat(getValueFromSupplier());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.