1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts.apicoverage; 18 19 import java.util.ArrayList; 20 import java.util.Collection; 21 import java.util.Collections; 22 import java.util.List; 23 24 /** Representation of a class in the API with constructors and methods. */ 25 class ApiClass implements Comparable<ApiClass>, HasCoverage { 26 27 private static final String VOID = "void"; 28 29 private final String mName; 30 31 private final boolean mDeprecated; 32 33 private final boolean mAbstract; 34 35 private final List<ApiConstructor> mApiConstructors = new ArrayList<ApiConstructor>(); 36 37 private final List<ApiMethod> mApiMethods = new ArrayList<ApiMethod>(); 38 39 private final String mSuperClassName; 40 41 private ApiClass mSuperClass; 42 43 /** 44 * @param name The name of the class 45 * @param deprecated true iff the class is marked as deprecated 46 * @param classAbstract true iff the class is abstract 47 * @param superClassName The fully qualified name of the super class 48 */ ApiClass( String name, boolean deprecated, boolean classAbstract, String superClassName)49 ApiClass( 50 String name, 51 boolean deprecated, 52 boolean classAbstract, 53 String superClassName) { 54 mName = name; 55 mDeprecated = deprecated; 56 mAbstract = classAbstract; 57 mSuperClassName = superClassName; 58 } 59 60 @Override compareTo(ApiClass another)61 public int compareTo(ApiClass another) { 62 return mName.compareTo(another.mName); 63 } 64 65 @Override getName()66 public String getName() { 67 return mName; 68 } 69 isDeprecated()70 public boolean isDeprecated() { 71 return mDeprecated; 72 } 73 getSuperClassName()74 public String getSuperClassName() { 75 return mSuperClassName; 76 } 77 isAbstract()78 public boolean isAbstract() { 79 return mAbstract; 80 } 81 setSuperClass(ApiClass superClass)82 public void setSuperClass(ApiClass superClass) { mSuperClass = superClass; } 83 addConstructor(ApiConstructor constructor)84 public void addConstructor(ApiConstructor constructor) { 85 mApiConstructors.add(constructor); 86 } 87 88 getConstructors()89 public Collection<ApiConstructor> getConstructors() { 90 return Collections.unmodifiableList(mApiConstructors); 91 } 92 addMethod(ApiMethod method)93 public void addMethod(ApiMethod method) { 94 mApiMethods.add(method); 95 } 96 97 /** Look for a matching constructor and mark it as covered */ markConstructorCovered(List<String> parameterTypes, String coveredbyApk)98 public void markConstructorCovered(List<String> parameterTypes, String coveredbyApk) { 99 if (mSuperClass != null) { 100 // Mark matching constructors in the superclass 101 mSuperClass.markConstructorCovered(parameterTypes, coveredbyApk); 102 } 103 ApiConstructor apiConstructor = getConstructor(parameterTypes); 104 if (apiConstructor != null) { 105 apiConstructor.setCovered(coveredbyApk); 106 } 107 108 } 109 110 /** Look for a matching method and if found and mark it as covered */ markMethodCovered( String name, List<String> parameterTypes, String returnType, String coveredbyApk)111 public void markMethodCovered( 112 String name, List<String> parameterTypes, String returnType, String coveredbyApk) { 113 if (mSuperClass != null) { 114 // Mark matching methods in the super class 115 mSuperClass.markMethodCovered(name, parameterTypes, returnType, coveredbyApk); 116 } 117 ApiMethod apiMethod = getMethod(name, parameterTypes, returnType); 118 if (apiMethod != null) { 119 apiMethod.setCovered(coveredbyApk); 120 } 121 } 122 getMethods()123 public Collection<ApiMethod> getMethods() { 124 return Collections.unmodifiableList(mApiMethods); 125 } 126 getNumCoveredMethods()127 public int getNumCoveredMethods() { 128 int numCovered = 0; 129 for (ApiConstructor constructor : mApiConstructors) { 130 if (constructor.isCovered()) { 131 numCovered++; 132 } 133 } 134 for (ApiMethod method : mApiMethods) { 135 if (method.isCovered()) { 136 numCovered++; 137 } 138 } 139 return numCovered; 140 } 141 getTotalMethods()142 public int getTotalMethods() { 143 return mApiConstructors.size() + mApiMethods.size(); 144 } 145 146 @Override getCoveragePercentage()147 public float getCoveragePercentage() { 148 if (getTotalMethods() == 0) { 149 return 100; 150 } else { 151 return (float) getNumCoveredMethods() / getTotalMethods() * 100; 152 } 153 } 154 155 @Override getMemberSize()156 public int getMemberSize() { 157 return getTotalMethods(); 158 } 159 getMethod(String name, List<String> parameterTypes, String returnType)160 private ApiMethod getMethod(String name, List<String> parameterTypes, String returnType) { 161 for (ApiMethod method : mApiMethods) { 162 boolean methodNameMatch = name.equals(method.getName()); 163 boolean parameterTypeMatch = 164 compareParameterTypes(method.getParameterTypes(), parameterTypes); 165 boolean returnTypeMatch = compareType(method.getReturnType(), returnType); 166 if (methodNameMatch && parameterTypeMatch && returnTypeMatch) { 167 return method; 168 } 169 } 170 return null; 171 } 172 173 /** 174 * The method compares two lists of parameters. If the {@code apiParameterTypeList} contains 175 * generic types, test parameter types are ignored. 176 * 177 * @param apiParameterTypeList The list of parameter types from the API 178 * @param testParameterTypeList The list of parameter types used in a test 179 * @return true iff the list of types are the same. 180 */ compareParameterTypes( List<String> apiParameterTypeList, List<String> testParameterTypeList)181 private static boolean compareParameterTypes( 182 List<String> apiParameterTypeList, List<String> testParameterTypeList) { 183 if (apiParameterTypeList.equals(testParameterTypeList)) { 184 return true; 185 } 186 if (apiParameterTypeList.size() != testParameterTypeList.size()) { 187 return false; 188 } 189 190 for (int i = 0; i < apiParameterTypeList.size(); i++) { 191 String apiParameterType = apiParameterTypeList.get(i); 192 String testParameterType = testParameterTypeList.get(i); 193 if (!compareType(apiParameterType, testParameterType)) { 194 return false; 195 } 196 } 197 return true; 198 } 199 200 /** 201 * @return true iff the parameter is a var arg parameter. 202 */ isVarArg(String parameter)203 private static boolean isVarArg(String parameter) { 204 return parameter.endsWith("..."); 205 } 206 207 /** 208 * Compare class types. 209 * @param apiType The type as reported by the api 210 * @param testType The type as found used in a test 211 * @return true iff the strings are equal, 212 * or the apiType is generic and the test type is not void 213 */ compareType(String apiType, String testType)214 private static boolean compareType(String apiType, String testType) { 215 return apiType.equals(testType) || 216 isGenericType(apiType) && !testType.equals(VOID) || 217 isGenericArrayType(apiType) && isArrayType(testType) || 218 isVarArg(apiType) && isArrayType(testType) && 219 apiType.startsWith(testType.substring(0, testType.indexOf("["))); 220 } 221 222 /** 223 * @return true iff the given parameterType is a generic type. 224 */ isGenericType(String type)225 private static boolean isGenericType(String type) { 226 return type.length() == 1 && 227 type.charAt(0) >= 'A' && 228 type.charAt(0) <= 'Z'; 229 } 230 231 /** 232 * @return true iff {@code type} ends with an []. 233 */ isArrayType(String type)234 private static boolean isArrayType(String type) { 235 return type.endsWith("[]"); 236 } 237 238 /** 239 * @return true iff the given parameterType is an array of generic type. 240 */ isGenericArrayType(String type)241 private static boolean isGenericArrayType(String type) { 242 return type.length() == 3 && isGenericType(type.substring(0, 1)) && isArrayType(type); 243 } 244 getConstructor(List<String> parameterTypes)245 private ApiConstructor getConstructor(List<String> parameterTypes) { 246 for (ApiConstructor constructor : mApiConstructors) { 247 if (compareParameterTypes(constructor.getParameterTypes(), parameterTypes)) { 248 return constructor; 249 } 250 } 251 return null; 252 } 253 } 254