Home | History | Annotate | Download | only in invocation
      1 /*
      2  * Copyright (c) 2007 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockito.internal.invocation;
      6 
      7 import java.lang.reflect.Method;
      8 
      9 import org.mockito.ArgumentMatcher;
     10 
     11 @SuppressWarnings({"unchecked","rawtypes"})
     12 public class TypeSafeMatching implements ArgumentMatcherAction {
     13 
     14     private final static ArgumentMatcherAction TYPE_SAFE_MATCHING_ACTION = new TypeSafeMatching();
     15 
     16     private TypeSafeMatching() {}
     17 
     18 
     19     public static ArgumentMatcherAction matchesTypeSafe(){
     20         return TYPE_SAFE_MATCHING_ACTION;
     21     }
     22     @Override
     23     public boolean apply(ArgumentMatcher matcher, Object argument) {
     24         return isCompatible(matcher, argument) && matcher.matches(argument);
     25     }
     26 
     27 
     28     /**
     29      * Returns <code>true</code> if the given <b>argument</b> can be passed to
     30      * the given <code>argumentMatcher</code> without causing a
     31      * {@link ClassCastException}.
     32      */
     33     private static boolean isCompatible(ArgumentMatcher<?> argumentMatcher, Object argument) {
     34         if (argument == null)
     35             return true;
     36 
     37         Class<?> expectedArgumentType = getArgumentType(argumentMatcher);
     38 
     39         return expectedArgumentType.isInstance(argument);
     40     }
     41 
     42     /**
     43      * Returns the type of {@link ArgumentMatcher#matches(Object)} of the given
     44      * {@link ArgumentMatcher} implementation.
     45      */
     46     private static Class<?> getArgumentType(ArgumentMatcher<?> argumentMatcher) {
     47         Method[] methods = argumentMatcher.getClass().getMethods();
     48 
     49         for (Method method : methods) {
     50             if (isMatchesMethod(method)) {
     51                 return method.getParameterTypes()[0];
     52             }
     53         }
     54         throw new NoSuchMethodError("Method 'matches(T)' not found in ArgumentMatcher: " + argumentMatcher + " !\r\n Please file a bug with this stack trace at: https://github.com/mockito/mockito/issues/new ");
     55     }
     56 
     57     /**
     58      * Returns <code>true</code> if the given method is
     59      * {@link ArgumentMatcher#matches(Object)}
     60      */
     61     private static boolean isMatchesMethod(Method method) {
     62         if (method.getParameterTypes().length != 1) {
     63             return false;
     64         }
     65         if (method.isBridge()) {
     66             return false;
     67         }
     68         return method.getName().equals("matches");
     69     }
     70 }
     71