Clover coverage report - Maven Clover report
Coverage timestamp: Sun Mar 18 2007 17:42:32 CET
file stats: LOC: 228   Methods: 3
NCLOC: 168   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
MethodSelectorImpl.java 89.5% 91.6% 100% 90.9%
coverage coverage
 1    package com.agical.rmock.core.util.impl;
 2   
 3    import java.lang.reflect.Constructor;
 4    import java.lang.reflect.Method;
 5    import java.lang.reflect.Modifier;
 6    import java.util.HashSet;
 7    import java.util.LinkedList;
 8    import java.util.Set;
 9    import java.util.SortedMap;
 10    import java.util.TreeMap;
 11   
 12    import com.agical.rmock.core.exception.NoSuchConstructorException;
 13    import com.agical.rmock.core.exception.NoSuchMethodException;
 14    import com.agical.rmock.core.util.MethodSelector;
 15   
 16    /**
 17    * @author brolund
 18    *
 19    * (c) 2005 Agical AB
 20    */
 21    public class MethodSelectorImpl implements MethodSelector {
 22   
 23  69 public Constructor getBestAssignableConstructor(Class clazz, Object[] arguments) {
 24  69 Constructor[] constructors = clazz.getDeclaredConstructors();
 25   
 26  69 if( constructors.length == 1 ) {
 27    // default constructor
 28  45 return constructors[0];
 29    }
 30   
 31  24 Set unAvailableConstructors = new HashSet();
 32  24 SortedMap sortedConstructors = new TreeMap();
 33  24 outer:
 34  136 for (int i = 0; i < constructors.length; i++) {
 35  112 Constructor constructor = constructors[i];
 36  112 Class[] classes = constructor.getParameterTypes();
 37   
 38  112 int score = 0;
 39   
 40    // Rule out if the constructor is of wrong size
 41  112 if( classes.length != arguments.length ) {
 42  23 unAvailableConstructors.add( new Integer( i ) );
 43  23 continue;
 44    }
 45   
 46    // Rule out private constructors
 47  89 if( Modifier.isPrivate( constructor.getModifiers() ) ) {
 48  1 unAvailableConstructors.add( new Integer( i ) );
 49  1 continue;
 50    }
 51   
 52  88 for (int j = 0; j < classes.length; j++) {
 53  92 Class targetParameterType = classes[j];
 54  92 Object parameter = arguments[j];
 55  92 Class parameterType = parameter==null?null:parameter.getClass();
 56   
 57    // Rule out to map null to a primitive
 58  92 if( targetParameterType.isPrimitive() && parameter == null ) {
 59  1 unAvailableConstructors.add( new Integer( i ) );
 60  1 continue outer;
 61    }
 62   
 63    // Rule out if one argument isn't assignable
 64  91 if( !(parameter==null || getAssignableDistance(targetParameterType, parameterType)!=-1 ) ) {
 65  60 unAvailableConstructors.add( new Integer( i ) );
 66  60 continue outer;
 67    }
 68    // Calculate the constructor distance
 69  31 score += getAssignableDistance( targetParameterType, parameterType );
 70    }
 71  27 sortedConstructors.put( new Integer( score ), constructor );
 72    }
 73  24 if( sortedConstructors.size() == 0 ) {
 74  1 throw new NoSuchConstructorException( clazz, arguments );
 75    }
 76   
 77  23 return (Constructor) sortedConstructors.get( sortedConstructors.firstKey() );
 78    }
 79   
 80    /**
 81    * Calculates the assignable distance between two classes. The distance between a primitive
 82    * and its object representation
 83    * is 1. The distance between the same classes are 0. If <code>assignmentClass</code> is not assignable to
 84    * <code>assignmentTargetClass</code> the distance is -1. If <code>assignmentClass</code> is null it
 85    * the distance is -1 if <code>assignmentTargetClass</code> is a primitive and 0 otherwise.
 86    * @param assignmentTargetClass The class to assign to
 87    * @param assignmentClass The assigned class. It cannot be a primitive class.
 88    * @return assignable distance between assignmentTargetClass and assignmentClass
 89    */
 90  133 int getAssignableDistance(Class assignmentTargetClass, Class assignmentClass) {
 91    // TODO: Rewrite this into a class hierarchy composite, and then apply a visitor
 92  133 int distance = -1;
 93   
 94  133 if( assignmentClass == null ) {
 95  6 if( assignmentTargetClass.isPrimitive() ) {
 96  1 throw new IllegalArgumentException( "Cannot assign null to a primitive" );
 97    }
 98  5 distance = 0;
 99  127 } else if( assignmentTargetClass.isPrimitive() ) {
 100  84 if( assignmentTargetClass.equals( assignmentClass ) ) {
 101  1 distance = 0;
 102    }
 103  84 if( assignmentTargetClass == Boolean.TYPE && assignmentClass == Boolean.class ) {
 104  2 distance = 1;
 105    }
 106  84 if( assignmentTargetClass == Byte.TYPE && assignmentClass == Byte.class ) {
 107  2 distance = 1;
 108    }
 109  84 if( assignmentTargetClass == Character.TYPE && assignmentClass == Character.class ) {
 110  2 distance = 1;
 111    }
 112  84 if( assignmentTargetClass == Short.TYPE && assignmentClass == Short.class ) {
 113  2 distance = 1;
 114    }
 115  84 if( assignmentTargetClass == Integer.TYPE && assignmentClass == Integer.class ) {
 116  13 distance = 1;
 117    }
 118  84 if( assignmentTargetClass == Long.TYPE && assignmentClass == Long.class ) {
 119  2 distance = 1;
 120    }
 121  84 if( assignmentTargetClass == Float.TYPE && assignmentClass == Float.class ) {
 122  2 distance = 1;
 123    }
 124  84 if( assignmentTargetClass == Double.TYPE && assignmentClass == Double.class ) {
 125  2 distance = 1;
 126    }
 127  43 } else if( assignmentTargetClass.isAssignableFrom(assignmentClass) ) {
 128    // Add stuff last in a list to make a breadth first search
 129  38 LinkedList inheritanceTree = new LinkedList();
 130   
 131  38 inheritanceTree.addLast( new LevelSeparator() );
 132  38 inheritanceTree.addLast( assignmentClass );
 133  124 while( !inheritanceTree.isEmpty() ) {
 134  124 Object tmp = (Object) inheritanceTree.removeFirst();
 135  124 if (tmp instanceof LevelSeparator) {
 136  53 distance++;
 137  53 if( !inheritanceTree.isEmpty() ) {
 138  53 inheritanceTree.addLast(tmp);
 139    }
 140    } else {
 141  71 Class cls = (Class) tmp;
 142  71 if( cls.equals( assignmentTargetClass ) ) {
 143  38 break;
 144    } else {
 145   
 146    // add super class and super interfaces to list if they are assignable.
 147  33 Class superClass = cls.getSuperclass();
 148  33 if( superClass != null ) {
 149  18 inheritanceTree.addLast( superClass );
 150    }
 151  33 Class[] interfaces = cls.getInterfaces();
 152  33 for (int i = 0; i < interfaces.length; i++) {
 153  39 if( assignmentTargetClass.isAssignableFrom( interfaces[i] ) ) {
 154  30 inheritanceTree.addLast( interfaces[i] );
 155    }
 156    }
 157    }
 158    }
 159    }
 160    } else {
 161  5 distance = -1;
 162    }
 163   
 164   
 165  132 return distance;
 166    }
 167   
 168    private class LevelSeparator {
 169    }
 170   
 171  1 public Method getBestAssignableMethod(Class clazz, Object[] arguments, String methodName) {
 172  1 Method[] methods = clazz.getMethods();
 173   
 174  1 Set unAvailableMethods = new HashSet();
 175  1 SortedMap sortedMethods = new TreeMap();
 176  1 outer:
 177  71 for (int i = 0; i < methods.length; i++) {
 178  70 Method method = methods[i];
 179  70 Class[] classes = method.getParameterTypes();
 180   
 181  70 int score = 0;
 182   
 183    // Rule out if method name is wrong
 184  70 if( !method.getName().equals( methodName ) ) {
 185  69 unAvailableMethods.add( new Integer( i ) );
 186  69 continue;
 187    }
 188   
 189    // Rule out if the methods number of arguments is of wrong
 190  1 if( classes.length != arguments.length ) {
 191  0 unAvailableMethods.add( new Integer( i ) );
 192  0 continue;
 193    }
 194   
 195    // Rule out private methods
 196  1 if( Modifier.isPrivate( method.getModifiers() ) ) {
 197  0 unAvailableMethods.add( new Integer( i ) );
 198  0 continue;
 199    }
 200   
 201  1 for (int j = 0; j < classes.length; j++) {
 202  4 Class targetParameterType = classes[j];
 203  4 Object parameter = arguments[j];
 204  4 Class parameterType = parameter==null?null:parameter.getClass();
 205   
 206    // Rule out to map null to a primitive
 207  4 if( targetParameterType.isPrimitive() && parameter == null ) {
 208  0 unAvailableMethods.add( new Integer( i ) );
 209  0 continue outer;
 210    }
 211   
 212    // Rule out if one argument isn't assignable
 213  4 if( !(parameter==null || getAssignableDistance(targetParameterType, parameterType)!=-1 ) ) {
 214  0 unAvailableMethods.add( new Integer( i ) );
 215  0 continue outer;
 216    }
 217    // Calculate the methods distance
 218  4 score += getAssignableDistance( targetParameterType, parameterType );
 219    }
 220  1 sortedMethods.put( new Integer( score ), method );
 221    }
 222  1 if( sortedMethods.size() == 0 ) {
 223  0 throw new NoSuchMethodException( clazz, methodName, arguments );
 224    }
 225   
 226  1 return (Method) sortedMethods.get( sortedMethods.firstKey() );
 227    }
 228    }