View Javadoc
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 }