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)98     public void markConstructorCovered(List<String> parameterTypes) {
99         if (mSuperClass != null) {
100             // Mark matching constructors in the superclass
101             mSuperClass.markConstructorCovered(parameterTypes);
102         }
103         ApiConstructor apiConstructor = getConstructor(parameterTypes);
104         if (apiConstructor != null) {
105             apiConstructor.setCovered(true);
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)111     public void markMethodCovered(String name, List<String> parameterTypes, String returnType) {
112         if (mSuperClass != null) {
113             // Mark matching methods in the super class
114             mSuperClass.markMethodCovered(name, parameterTypes, returnType);
115         }
116         ApiMethod apiMethod = getMethod(name, parameterTypes, returnType);
117         if (apiMethod != null) {
118             apiMethod.setCovered(true);
119         }
120     }
121 
getMethods()122     public Collection<ApiMethod> getMethods() {
123         return Collections.unmodifiableList(mApiMethods);
124     }
125 
getNumCoveredMethods()126     public int getNumCoveredMethods() {
127         int numCovered = 0;
128         for (ApiConstructor constructor : mApiConstructors) {
129             if (constructor.isCovered()) {
130                 numCovered++;
131             }
132         }
133         for (ApiMethod method : mApiMethods) {
134             if (method.isCovered()) {
135                 numCovered++;
136             }
137         }
138         return numCovered;
139     }
140 
getTotalMethods()141     public int getTotalMethods() {
142         return mApiConstructors.size() + mApiMethods.size();
143     }
144 
145     @Override
getCoveragePercentage()146     public float getCoveragePercentage() {
147         if (getTotalMethods() == 0) {
148             return 100;
149         } else {
150             return (float) getNumCoveredMethods() / getTotalMethods() * 100;
151         }
152     }
153 
154     @Override
getMemberSize()155     public int getMemberSize() {
156         return getTotalMethods();
157     }
158 
getMethod(String name, List<String> parameterTypes, String returnType)159     private ApiMethod getMethod(String name, List<String> parameterTypes, String returnType) {
160         for (ApiMethod method : mApiMethods) {
161             boolean methodNameMatch = name.equals(method.getName());
162             boolean parameterTypeMatch =
163                     compareParameterTypes(method.getParameterTypes(), parameterTypes);
164             boolean returnTypeMatch = compareType(method.getReturnType(), returnType);
165             if (methodNameMatch && parameterTypeMatch && returnTypeMatch) {
166                 return method;
167             }
168         }
169         return null;
170     }
171 
172     /**
173      * The method compares two lists of parameters. If the {@code apiParameterTypeList} contains
174      * generic types, test parameter types are ignored.
175      *
176      * @param apiParameterTypeList The list of parameter types from the API
177      * @param testParameterTypeList The list of parameter types used in a test
178      * @return true iff the list of types are the same.
179      */
compareParameterTypes( List<String> apiParameterTypeList, List<String> testParameterTypeList)180     private static boolean compareParameterTypes(
181             List<String> apiParameterTypeList, List<String> testParameterTypeList) {
182         if (apiParameterTypeList.equals(testParameterTypeList)) {
183             return true;
184         }
185         if (apiParameterTypeList.size() != testParameterTypeList.size()) {
186             return false;
187         }
188 
189         for (int i = 0; i < apiParameterTypeList.size(); i++) {
190             String apiParameterType = apiParameterTypeList.get(i);
191             String testParameterType = testParameterTypeList.get(i);
192             if (!compareType(apiParameterType, testParameterType)) {
193                 return false;
194             }
195         }
196         return true;
197     }
198 
199     /**
200      * @return true iff the parameter is a var arg parameter.
201      */
isVarArg(String parameter)202     private static boolean isVarArg(String parameter) {
203         return parameter.endsWith("...");
204     }
205 
206     /**
207      * Compare class types.
208      * @param apiType The type as reported by the api
209      * @param testType The type as found used in a test
210      * @return true iff the strings are equal,
211      * or the apiType is generic and the test type is not void
212      */
compareType(String apiType, String testType)213     private static boolean compareType(String apiType, String testType) {
214         return apiType.equals(testType) ||
215                 isGenericType(apiType) && !testType.equals(VOID) ||
216                 isGenericArrayType(apiType) && isArrayType(testType) ||
217                 isVarArg(apiType) && isArrayType(testType) &&
218                         apiType.startsWith(testType.substring(0, testType.indexOf("[")));
219     }
220 
221     /**
222      * @return true iff the given parameterType is a generic type.
223      */
isGenericType(String type)224     private static boolean isGenericType(String type) {
225         return type.length() == 1 &&
226                 type.charAt(0) >= 'A' &&
227                 type.charAt(0) <= 'Z';
228     }
229 
230     /**
231      * @return true iff {@code type} ends with an [].
232      */
isArrayType(String type)233     private static boolean isArrayType(String type) {
234         return type.endsWith("[]");
235     }
236 
237     /**
238      * @return true iff the given parameterType is an array of generic type.
239      */
isGenericArrayType(String type)240     private static boolean isGenericArrayType(String type) {
241         return type.length() == 3 && isGenericType(type.substring(0, 1)) && isArrayType(type);
242     }
243 
getConstructor(List<String> parameterTypes)244     private ApiConstructor getConstructor(List<String> parameterTypes) {
245         for (ApiConstructor constructor : mApiConstructors) {
246             if (compareParameterTypes(constructor.getParameterTypes(), parameterTypes)) {
247                 return constructor;
248             }
249         }
250         return null;
251     }
252 }
253