View Javadoc

1   /*
2    * Copyright (c) 2014 Contextream, Inc. and others.  All rights reserved.
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6    * and is available at http://www.eclipse.org/legal/epl-v10.html
7    */
8   
9   package org.opendaylight.lispflowmapping.tools.junit;
10  
11  import java.lang.reflect.Field;
12  import java.lang.reflect.InvocationTargetException;
13  import java.lang.reflect.Method;
14  import java.util.ArrayList;
15  import java.util.Arrays;
16  import java.util.HashSet;
17  import java.util.List;
18  import java.util.Set;
19  
20  import org.hamcrest.BaseMatcher;
21  import org.hamcrest.Description;
22  import org.hamcrest.Matcher;
23  import org.hamcrest.TypeSafeMatcher;
24  import org.jmock.Expectations;
25  import org.jmock.Mockery;
26  import org.jmock.api.Action;
27  import org.jmock.api.Invocation;
28  import org.jmock.internal.InvocationExpectationBuilder;
29  import org.jmock.internal.ReturnDefaultValueAction;
30  import org.jmock.lib.concurrent.Synchroniser;
31  import org.jmock.lib.legacy.ClassImposteriser;
32  import org.jmock.syntax.ReceiverClause;
33  import org.junit.After;
34  import org.junit.Assert;
35  import org.junit.Before;
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  
39  public abstract class BaseExpectations extends Expectations {
40      protected Mockery context;
41      protected boolean showAllExpectations;
42      private final Synchroniser synchroniser = new Synchroniser();
43      protected static final Logger LOG = LoggerFactory.getLogger(BaseExpectations.class);
44  
45      @Before
46      public void before() throws Exception {
47          context = new Mockery() {
48              {
49                  setImposteriser(ClassImposteriser.INSTANCE);
50                  setThreadingPolicy(synchroniser); // otherwise we get errors on
51                  // the finalizer thread
52              }
53          };
54          defaultAction = new ReturnDefaultValueAction(ClassImposteriser.INSTANCE);
55      }
56  
57      @After
58      public void after() throws Exception {
59          context.assertIsSatisfied();
60      }
61  
62      // New suger syntax
63  
64      protected final void ret(Object result) {
65          will(returnValue(result));
66      }
67  
68      protected final void rethrow(Throwable throwable) {
69          will(throwException(throwable));
70      }
71  
72      protected final void retField(Object container, String fieldName) throws Exception {
73          will(new ReturnField(container, fieldName));
74      }
75  
76      protected final void rets(Object... results) {
77          will(returnValues(results));
78      }
79  
80      protected final <T> T wany(Class<T> type) {
81          return with(any(type));
82      }
83  
84      protected final int wanyint() {
85          return with(any(int.class));
86      }
87  
88      protected final long wanylong() {
89          return with(any(long.class));
90      }
91  
92      protected final boolean wanybool() {
93          return with(any(boolean.class));
94      }
95  
96      protected final <T> T wsame(T instance) {
97          return with(same(instance));
98      }
99  
100     protected final <T> T weq(T instance) {
101         return with(equal(instance));
102     }
103 
104     protected final short weq(short instance) {
105         return with(equal(instance));
106     }
107 
108     protected final int weq(int instance) {
109         return with(equal(instance));
110     }
111 
112     protected final long weq(long instance) {
113         return with(equal(instance));
114     }
115 
116     protected final boolean weq(boolean instance) {
117         return with(equal(instance));
118     }
119 
120     public static Action returnValues(Object... result) {
121         return new ActionSequenceValue(result);
122     }
123 
124     protected void retMethod(final String methodName) {
125         will(new MethodAction(this, methodName));
126     }
127 
128     private static class MethodAction implements Action {
129         private Object testInstance;
130         private String methodName;
131         private Method method;
132 
133         public MethodAction(Object testInstance, String methodName) {
134             this.testInstance = testInstance;
135             this.methodName = methodName;
136             method = findMethod(testInstance.getClass());
137             Assert.assertNotNull("Cannot locate '" + methodName + "'", method);
138         }
139 
140         private Method findMethod(Class<? extends Object> clazz) {
141             if (Object.class.equals(clazz)) {
142                 return null;
143             }
144             try {
145                 return clazz.getMethod(methodName, Invocation.class);
146             } catch (SecurityException e) {
147                 LOG.debug("Catched SecurityException", e);
148             } catch (NoSuchMethodException e) {
149                 LOG.debug("Catched NoSuchMethodException", e);
150             }
151 
152             return findMethod(clazz.getSuperclass());
153         }
154 
155         public void describeTo(Description arg0) {
156             arg0.appendText("running " + methodName);
157         }
158 
159         public Object invoke(Invocation invocation) throws Throwable {
160             Exception e = null;
161             try {
162                 return method.invoke(testInstance, invocation);
163             } catch (SecurityException se) {
164                 e = se;
165             } catch (IllegalAccessException iae) {
166                 e = iae;
167             } catch (InvocationTargetException ite) {
168                 throw ite.getTargetException();
169             }
170             Assert.fail("Got " + e.getMessage() + " while trying to execute '" + methodName + "'");
171             return null;
172         }
173 
174     }
175 
176     private static class ActionSequenceValue implements Action {
177         private final Object[] values;
178         private int i = 0;
179 
180         public ActionSequenceValue(Object... values) {
181             this.values = values;
182         }
183 
184         public Object invoke(Invocation invocation) throws Throwable {
185             if (i < values.length) {
186                 return values[i++];
187             }
188             throw new RuntimeException("no morCxtrmExpectationse actions available: " + invocation);
189         }
190 
191         public void describeTo(Description description) {
192             description.appendText(", and then ").appendText(Arrays.toString(values));
193         }
194     }
195 
196     protected static final class ReturnField implements Action {
197         private final Object container;
198         private final Field field;
199 
200         public ReturnField(Object container, String fieldName) throws Exception {
201             this.container = container;
202             field = container.getClass().getDeclaredField(fieldName);
203             field.setAccessible(true);
204         }
205 
206         public void describeTo(Description description) {
207             description.appendText("return " + container.getClass().getName() + "." + field.getName());
208         }
209 
210         public Object invoke(Invocation invocation) throws Throwable {
211             return field.get(container);
212         }
213     }
214 
215     public static class ValueSaverAction<T> extends BaseMatcher<T> implements Action {
216         private final String logMatch;
217         private final boolean logInvocation;
218         public T lastValue;
219         public final List<T> values = new ArrayList<T>();
220 
221         public ValueSaverAction() {
222             this(null, false);
223         }
224 
225         public ValueSaverAction(String logMatch, boolean logInvocation) {
226             this.logMatch = logMatch;
227             this.logInvocation = logInvocation;
228         }
229 
230         @SuppressWarnings("unchecked")
231         public final boolean matches(Object arg) {
232             T value = (T) arg;
233             if (!validate(value)) {
234                 return false;
235             }
236             lastValue = transformOnMatch(value);
237             values.add(lastValue);
238             boolean match = match(lastValue);
239             if (match && (logMatch != null)) {
240                 LOG.trace("Match: " + logMatch + " " + value);
241             }
242             return match;
243         }
244 
245         protected T onMatch(T value) {
246             return value;
247         }
248 
249         protected boolean match(T lastValue2) {
250             return true;
251         }
252 
253         protected boolean validate(T value) {
254             return true;
255         }
256 
257         protected T transformOnMatch(T value) {
258             return value;
259         }
260 
261         public void describeTo(Description arg0) {
262         }
263 
264         public Object invoke(Invocation invocation) throws Throwable {
265             if (logInvocation) {
266                 LOG.trace("Invoke: returning " + lastValue);
267             }
268             return lastValue;
269         }
270 
271         @Override
272         public String toString() {
273             return "ValueSavers: " + values.toString();
274         }
275     }
276 
277     @SafeVarargs
278     protected final static <T> Matcher<T[]> contains(final T... expected) {
279         return new BaseMatcher<T[]>() {
280             @SuppressWarnings("unchecked")
281             public boolean matches(Object actual) {
282                 T[] arr = (T[]) actual;
283                 if (arr.length != expected.length) {
284                     return false;
285                 }
286                 for (T expectedInstance : expected) {
287                     boolean found = false;
288                     for (int j = 0; (j < arr.length) && !found; j++) {
289                         found = (arr[j] == expectedInstance);
290                     }
291                     if (!found) {
292                         return false;
293                     }
294                 }
295                 return true;
296             }
297 
298             public void describeTo(Description arg0) {
299             }
300         };
301     }
302 
303     @SafeVarargs
304     protected final static <T> Matcher<T[]> sameArbitraryArray(final T... expectedArr) {
305         return new TypeSafeMatcher<T[]>() {
306             @Override
307             public boolean matchesSafely(T[] actualArr) {
308                 Set<T> expected = new HashSet<T>();
309                 for (T val : expectedArr) {
310                     expected.add(val);
311                 }
312                 Set<T> actual = new HashSet<T>();
313                 actual.addAll(Arrays.asList(actualArr));
314                 return actual.equals(expected);
315             }
316 
317             public void describeTo(Description description) {
318                 description.appendText("Same arbitrary array as " + Arrays.toString(expectedArr));
319             }
320         };
321     }
322 
323     @SafeVarargs
324     protected final static <T> Matcher<T[]> doseNotContain(final T... forbiddenValues) {
325         return new TypeSafeMatcher<T[]>() {
326             @Override
327             public boolean matchesSafely(T[] arr) {
328                 for (T forbiddenInstance : forbiddenValues) {
329                     for (T element : arr) {
330                         if (element == forbiddenInstance) {
331                             return false;
332                         }
333                     }
334                 }
335                 return true;
336             }
337 
338             public void describeTo(Description description) {
339             }
340         };
341     }
342 
343     public class StringArrayMatcher extends BaseMatcher<String[]> {
344         private final Object[] expected;
345 
346         /**
347          * @param expected
348          *            null are considered "any"
349          */
350         private StringArrayMatcher(Object... expected) {
351             this.expected = expected;
352         }
353 
354         public boolean matches(Object item) {
355             if (!(item instanceof String[])) {
356                 return false;
357             }
358             String[] actual = (String[]) item;
359             if (expected.length != actual.length) {
360                 return false;
361             }
362             for (int i = 0; i < expected.length; i++) {
363                 if ((expected[i] != null) && !expected[i].toString().equals(actual[i])) {
364                     return false;
365                 }
366             }
367             return true;
368         }
369 
370         public void describeTo(Description description) {
371             description.appendText("String" + Arrays.toString(expected));
372         }
373     }
374 
375     /**
376      * @param expected
377      *            null are considered "any"
378      */
379     public final String[] wStrArr(Object... expected) {
380         return with(new StringArrayMatcher(expected));
381     }
382 
383     // ////////////////////////////////////////////////////////////
384     // Make expectations work in our new ConteXtream better way //
385     // ////////////////////////////////////////////////////////////
386     private ReturnDefaultValueAction defaultAction;
387 
388     protected InvocationExpectationBuilder getCurrentBuilder() {
389         try {
390             return currentBuilder();
391         } catch (IllegalStateException e) {
392             LOG.debug("Catched IllegalStateException", e);
393             return null;
394         }
395     }
396 
397     private void addCurrentExpectation() {
398         context.addExpectation(currentBuilder().toExpectation(defaultAction));
399     }
400 
401     @Override
402     public ReceiverClause exactly(int count) {
403         ReceiverClause ret = super.exactly(count);
404         addCurrentExpectation();
405         return ret;
406     }
407 
408     @Override
409     public ReceiverClause atLeast(int count) {
410         ReceiverClause ret = super.atLeast(count);
411         addCurrentExpectation();
412         return ret;
413     }
414 
415     @Override
416     public ReceiverClause between(int minCount, int maxCount) {
417         ReceiverClause ret = super.between(minCount, maxCount);
418         addCurrentExpectation();
419         return ret;
420     }
421 
422     @Override
423     public ReceiverClause atMost(int count) {
424         ReceiverClause ret = super.atMost(count);
425         addCurrentExpectation();
426         return ret;
427     }
428 
429 }