1 package org.junit.tests.experimental.theories.extendingwithstubs; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 import java.util.ArrayList; 7 import java.util.HashMap; 8 import java.util.List; 9 import java.util.Map.Entry; 10 import java.util.Random; 11 12 import org.hamcrest.BaseDescription; 13 import org.hamcrest.Description; 14 import org.junit.internal.AssumptionViolatedException; 15 16 public class Guesser<T> extends ReguessableValue { 17 static class GuessMap extends HashMap<MethodCall, Object> implements 18 InvocationHandler { 19 private static final long serialVersionUID = 1L; 20 21 public GuessMap(GuessMap guesses) { 22 super(guesses); 23 } 24 25 public GuessMap() { 26 } 27 28 GuessMap replaceGuess(Object oldValue, Object newValue) { 29 GuessMap newGuesses = new GuessMap(this); 30 for (Entry<MethodCall, Object> entry : newGuesses.entrySet()) { 31 if (entry.getValue().equals(oldValue)) { 32 entry.setValue(newValue); 33 } 34 } 35 return newGuesses; 36 } 37 38 protected Object generateGuess(Class<?> returnType) { 39 if (returnType.equals(String.class)) { 40 return "GUESS" + new Random().nextInt(); 41 } 42 if (returnType.equals(Integer.class) 43 || returnType.equals(int.class)) { 44 return new Random().nextInt(); 45 } 46 return null; 47 } 48 49 Object getGuess(MethodCall call) { 50 if (!containsKey(call)) { 51 put(call, generateGuess(call.getReturnType())); 52 } 53 return get(call); 54 } 55 56 public Object invoke(Object proxy, Method method, Object[] args) 57 throws Throwable { 58 return getGuess(new MethodCall(method, args)); 59 } 60 } 61 62 private final GuessMap guesses; 63 64 private final Class<? extends T> type; 65 66 public Guesser(Class<? extends T> type) { 67 this(type, new GuessMap()); 68 } 69 70 public Guesser(Class<? extends T> type2, GuessMap guesses) { 71 this.type = type2; 72 this.guesses = guesses; 73 } 74 75 @SuppressWarnings("unchecked") 76 public T getProxy() { 77 return (T) Proxy.newProxyInstance(getClass().getClassLoader(), 78 new Class[]{getType()}, guesses); 79 } 80 81 @Override 82 public List<ReguessableValue> reguesses(AssumptionViolatedException e) { 83 final ArrayList<ReguessableValue> returnThis = new ArrayList<ReguessableValue>(); 84 e.describeTo(new BaseDescription() { 85 @Override 86 protected void append(char arg0) { 87 } 88 89 boolean expectedSeen = false; 90 Object expected = null; 91 92 @Override 93 public Description appendValue(Object value) { 94 noteValue(value); 95 return super.appendValue(value); 96 } 97 98 private void noteValue(Object value) { 99 if (!expectedSeen) { 100 expected = value; 101 expectedSeen = true; 102 return; 103 } 104 105 GuessMap newGuesses = guesses.replaceGuess(expected, value); 106 returnThis.add(new Guesser<T>(getType(), newGuesses)); 107 } 108 }); 109 return returnThis; 110 } 111 112 @Override 113 public Object getValue() throws CouldNotGenerateValueException { 114 return getProxy(); 115 } 116 117 public Class<? extends T> getType() { 118 return type; 119 } 120 121 @Override 122 public String getDescription() throws CouldNotGenerateValueException { 123 return "guesser[" + type + "]"; 124 } 125 126 }