blob: e57a3b3206166732583ff110d786665f56ca7700 [file] [log] [blame]
package org.junit.tests.experimental.theories.extendingwithstubs;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Random;
import org.hamcrest.BaseDescription;
import org.hamcrest.Description;
import org.junit.internal.AssumptionViolatedException;
public class Guesser<T> extends ReguessableValue {
static class GuessMap extends HashMap<MethodCall, Object> implements
InvocationHandler {
private static final long serialVersionUID = 1L;
public GuessMap(GuessMap guesses) {
super(guesses);
}
public GuessMap() {
}
GuessMap replaceGuess(Object oldValue, Object newValue) {
GuessMap newGuesses = new GuessMap(this);
for (Entry<MethodCall, Object> entry : newGuesses.entrySet()) {
if (entry.getValue().equals(oldValue)) {
entry.setValue(newValue);
}
}
return newGuesses;
}
protected Object generateGuess(Class<?> returnType) {
if (returnType.equals(String.class)) {
return "GUESS" + new Random().nextInt();
}
if (returnType.equals(Integer.class)
|| returnType.equals(int.class)) {
return new Random().nextInt();
}
return null;
}
Object getGuess(MethodCall call) {
if (!containsKey(call)) {
put(call, generateGuess(call.getReturnType()));
}
return get(call);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return getGuess(new MethodCall(method, args));
}
}
private final GuessMap guesses;
private final Class<? extends T> type;
public Guesser(Class<? extends T> type) {
this(type, new GuessMap());
}
public Guesser(Class<? extends T> type2, GuessMap guesses) {
this.type = type2;
this.guesses = guesses;
}
@SuppressWarnings("unchecked")
public T getProxy() {
return (T) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{getType()}, guesses);
}
@Override
public List<ReguessableValue> reguesses(AssumptionViolatedException e) {
final ArrayList<ReguessableValue> returnThis = new ArrayList<ReguessableValue>();
e.describeTo(new BaseDescription() {
@Override
protected void append(char arg0) {
}
boolean expectedSeen = false;
Object expected = null;
@Override
public Description appendValue(Object value) {
noteValue(value);
return super.appendValue(value);
}
private void noteValue(Object value) {
if (!expectedSeen) {
expected = value;
expectedSeen = true;
return;
}
GuessMap newGuesses = guesses.replaceGuess(expected, value);
returnThis.add(new Guesser<T>(getType(), newGuesses));
}
});
return returnThis;
}
@Override
public Object getValue() throws CouldNotGenerateValueException {
return getProxy();
}
public Class<? extends T> getType() {
return type;
}
@Override
public String getDescription() throws CouldNotGenerateValueException {
return "guesser[" + type + "]";
}
}