Rename static final variable 'logger' to 'LOG'
[lispflowmapping.git] / commons / unittest_tools / src / main / java / org / opendaylight / lispflowmapping / tools / junit / BaseExpectations.java
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 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             } catch (NoSuchMethodException e) {
148             }
149
150             return findMethod(clazz.getSuperclass());
151         }
152
153         public void describeTo(Description arg0) {
154             arg0.appendText("running " + methodName);
155         }
156
157         public Object invoke(Invocation invocation) throws Throwable {
158             Exception e = null;
159             try {
160                 return method.invoke(testInstance, invocation);
161             } catch (SecurityException se) {
162                 e = se;
163             } catch (IllegalAccessException iae) {
164                 e = iae;
165             } catch (InvocationTargetException ite) {
166                 throw ite.getTargetException();
167             }
168             Assert.fail("Got " + e.getMessage() + " while trying to execute '" + methodName + "'");
169             return null;
170         }
171
172     }
173
174     private static class ActionSequenceValue implements Action {
175         private final Object[] values;
176         private int i = 0;
177
178         public ActionSequenceValue(Object... values) {
179             this.values = values;
180         }
181
182         public Object invoke(Invocation invocation) throws Throwable {
183             if (i < values.length) {
184                 return values[i++];
185             }
186             throw new RuntimeException("no morCxtrmExpectationse actions available: " + invocation);
187         }
188
189         public void describeTo(Description description) {
190             description.appendText(", and then ").appendText(Arrays.toString(values));
191         }
192     }
193
194     protected static final class ReturnField implements Action {
195         private final Object container;
196         private final Field field;
197
198         public ReturnField(Object container, String fieldName) throws Exception {
199             this.container = container;
200             field = container.getClass().getDeclaredField(fieldName);
201             field.setAccessible(true);
202         }
203
204         public void describeTo(Description description) {
205             description.appendText("return " + container.getClass().getName() + "." + field.getName());
206         }
207
208         public Object invoke(Invocation invocation) throws Throwable {
209             return field.get(container);
210         }
211     }
212
213     public static class ValueSaverAction<T> extends BaseMatcher<T> implements Action {
214         private final String logMatch;
215         private final boolean logInvocation;
216         public T lastValue;
217         public final List<T> values = new ArrayList<T>();
218
219         public ValueSaverAction() {
220             this(null, false);
221         }
222
223         public ValueSaverAction(String logMatch, boolean logInvocation) {
224             this.logMatch = logMatch;
225             this.logInvocation = logInvocation;
226         }
227
228         @SuppressWarnings("unchecked")
229         public final boolean matches(Object arg) {
230             T value = (T) arg;
231             if (!validate(value)) {
232                 return false;
233             }
234             lastValue = transformOnMatch(value);
235             values.add(lastValue);
236             boolean match = match(lastValue);
237             if (match && (logMatch != null)) {
238                 LOG.trace("Match: " + logMatch + " " + value);
239             }
240             return match;
241         }
242
243         protected T onMatch(T value) {
244             return value;
245         }
246
247         protected boolean match(T lastValue2) {
248             return true;
249         }
250
251         protected boolean validate(T value) {
252             return true;
253         }
254
255         protected T transformOnMatch(T value) {
256             return value;
257         }
258
259         public void describeTo(Description arg0) {
260         }
261
262         public Object invoke(Invocation invocation) throws Throwable {
263             if (logInvocation) {
264                 LOG.trace("Invoke: returning " + lastValue);
265             }
266             return lastValue;
267         }
268
269         @Override
270         public String toString() {
271             return "ValueSavers: " + values.toString();
272         }
273     }
274
275     @SafeVarargs
276     protected final static <T> Matcher<T[]> contains(final T... expected) {
277         return new BaseMatcher<T[]>() {
278             @SuppressWarnings("unchecked")
279             public boolean matches(Object actual) {
280                 T[] arr = (T[]) actual;
281                 if (arr.length != expected.length) {
282                     return false;
283                 }
284                 for (T expectedInstance : expected) {
285                     boolean found = false;
286                     for (int j = 0; (j < arr.length) && !found; j++) {
287                         found = (arr[j] == expectedInstance);
288                     }
289                     if (!found) {
290                         return false;
291                     }
292                 }
293                 return true;
294             }
295
296             public void describeTo(Description arg0) {
297             }
298         };
299     }
300
301     @SafeVarargs
302     protected final static <T> Matcher<T[]> sameArbitraryArray(final T... expectedArr) {
303         return new TypeSafeMatcher<T[]>() {
304             @Override
305             public boolean matchesSafely(T[] actualArr) {
306                 Set<T> expected = new HashSet<T>();
307                 for (T val : expectedArr) {
308                     expected.add(val);
309                 }
310                 Set<T> actual = new HashSet<T>();
311                 actual.addAll(Arrays.asList(actualArr));
312                 return actual.equals(expected);
313             }
314
315             public void describeTo(Description description) {
316                 description.appendText("Same arbitrary array as " + Arrays.toString(expectedArr));
317             }
318         };
319     }
320
321     @SafeVarargs
322     protected final static <T> Matcher<T[]> doseNotContain(final T... forbiddenValues) {
323         return new TypeSafeMatcher<T[]>() {
324             @Override
325             public boolean matchesSafely(T[] arr) {
326                 for (T forbiddenInstance : forbiddenValues) {
327                     for (T element : arr) {
328                         if (element == forbiddenInstance) {
329                             return false;
330                         }
331                     }
332                 }
333                 return true;
334             }
335
336             public void describeTo(Description description) {
337             }
338         };
339     }
340
341     public class StringArrayMatcher extends BaseMatcher<String[]> {
342         private final Object[] expected;
343
344         /**
345          * @param expected
346          *            null are considered "any"
347          */
348         private StringArrayMatcher(Object... expected) {
349             this.expected = expected;
350         }
351
352         public boolean matches(Object item) {
353             if (!(item instanceof String[])) {
354                 return false;
355             }
356             String[] actual = (String[]) item;
357             if (expected.length != actual.length) {
358                 return false;
359             }
360             for (int i = 0; i < expected.length; i++) {
361                 if ((expected[i] != null) && !expected[i].toString().equals(actual[i])) {
362                     return false;
363                 }
364             }
365             return true;
366         }
367
368         public void describeTo(Description description) {
369             description.appendText("String" + Arrays.toString(expected));
370         }
371     }
372
373     /**
374      * @param expected
375      *            null are considered "any"
376      */
377     public final String[] wStrArr(Object... expected) {
378         return with(new StringArrayMatcher(expected));
379     }
380
381     // ////////////////////////////////////////////////////////////
382     // Make expectations work in our new ConteXtream better way //
383     // ////////////////////////////////////////////////////////////
384     private ReturnDefaultValueAction defaultAction;
385
386     protected InvocationExpectationBuilder getCurrentBuilder() {
387         try {
388             return currentBuilder();
389         } catch (IllegalStateException e) {
390             return null;
391         }
392     }
393
394     private void addCurrentExpectation() {
395         context.addExpectation(currentBuilder().toExpectation(defaultAction));
396     }
397
398     @Override
399     public ReceiverClause exactly(int count) {
400         ReceiverClause ret = super.exactly(count);
401         addCurrentExpectation();
402         return ret;
403     }
404
405     @Override
406     public ReceiverClause atLeast(int count) {
407         ReceiverClause ret = super.atLeast(count);
408         addCurrentExpectation();
409         return ret;
410     }
411
412     @Override
413     public ReceiverClause between(int minCount, int maxCount) {
414         ReceiverClause ret = super.between(minCount, maxCount);
415         addCurrentExpectation();
416         return ret;
417     }
418
419     @Override
420     public ReceiverClause atMost(int count) {
421         ReceiverClause ret = super.atMost(count);
422         addCurrentExpectation();
423         return ret;
424     }
425
426 }