Home | History | Annotate | Download | only in apicoverage
      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      */
     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
     61     public int compareTo(ApiClass another) {
     62         return mName.compareTo(another.mName);
     63     }
     64 
     65     @Override
     66     public String getName() {
     67         return mName;
     68     }
     69 
     70     public boolean isDeprecated() {
     71         return mDeprecated;
     72     }
     73 
     74     public String getSuperClassName() {
     75         return mSuperClassName;
     76     }
     77 
     78     public boolean isAbstract() {
     79         return mAbstract;
     80     }
     81 
     82     public void setSuperClass(ApiClass superClass) { mSuperClass = superClass; }
     83 
     84     public void addConstructor(ApiConstructor constructor) {
     85         mApiConstructors.add(constructor);
     86     }
     87 
     88 
     89     public Collection<ApiConstructor> getConstructors() {
     90         return Collections.unmodifiableList(mApiConstructors);
     91     }
     92 
     93     public void addMethod(ApiMethod method) {
     94         mApiMethods.add(method);
     95     }
     96 
     97     /** Look for a matching constructor and mark it as covered */
     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 */
    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 
    122     public Collection<ApiMethod> getMethods() {
    123         return Collections.unmodifiableList(mApiMethods);
    124     }
    125 
    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 
    141     public int getTotalMethods() {
    142         return mApiConstructors.size() + mApiMethods.size();
    143     }
    144 
    145     @Override
    146     public float getCoveragePercentage() {
    147         if (getTotalMethods() == 0) {
    148             return 100;
    149         } else {
    150             return (float) getNumCoveredMethods() / getTotalMethods() * 100;
    151         }
    152     }
    153 
    154     @Override
    155     public int getMemberSize() {
    156         return getTotalMethods();
    157     }
    158 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    240     private static boolean isGenericArrayType(String type) {
    241         return type.length() == 3 && isGenericType(type.substring(0, 1)) && isArrayType(type);
    242     }
    243 
    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