CTS Coverage Report Support for generic types

Methods and constructors with generic parameter types or
return types were not counted as covered. The solution
is to check if the types from the API are generic and if
so, ignore the type reported by dexdeps

bug: 19272826
Change-Id: If0e7ef4ad3c78511bd2fe7c70117b55fb10c2110
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java
index f5abd5e5..73cea67 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiClass.java
@@ -24,6 +24,8 @@
 /** Representation of a class in the API with constructors and methods. */
 class ApiClass implements Comparable<ApiClass>, HasCoverage {
 
+    private static final String VOID = "void";
+
     private final String mName;
 
     private final boolean mDeprecated;
@@ -156,18 +158,83 @@
 
     private ApiMethod getMethod(String name, List<String> parameterTypes, String returnType) {
         for (ApiMethod method : mApiMethods) {
-            if (name.equals(method.getName())
-                    && parameterTypes.equals(method.getParameterTypes())
-                    && returnType.equals(method.getReturnType())) {
+            boolean methodNameMatch = name.equals(method.getName());
+            boolean parameterTypeMatch =
+                    compareParameterTypes(method.getParameterTypes(), parameterTypes);
+            boolean returnTypeMatch = compareType(method.getReturnType(), returnType);
+            if (methodNameMatch && parameterTypeMatch && returnTypeMatch) {
                 return method;
             }
         }
         return null;
     }
 
+    /**
+     * The method compares two lists of parameters. If the {@code apiParameterTypeList} contains
+     * generic types, test parameter types are ignored.
+     *
+     * @param apiParameterTypeList The list of parameter types from the API
+     * @param testParameterTypeList The list of parameter types used in a test
+     * @return true iff the list of types are the same.
+     */
+    private static boolean compareParameterTypes(
+            List<String> apiParameterTypeList, List<String> testParameterTypeList) {
+        if (apiParameterTypeList.equals(testParameterTypeList)) {
+            return true;
+        }
+        if (apiParameterTypeList.size() != testParameterTypeList.size()) {
+            return false;
+        }
+
+        for (int i = 0; i < apiParameterTypeList.size(); i++) {
+            String apiParameterType = apiParameterTypeList.get(i);
+            String testParameterType = testParameterTypeList.get(i);
+            if (!compareType(apiParameterType, testParameterType)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Compare class types.
+     * @param apiType The type as reported by the api
+     * @param testType The type as found used in a test
+     * @return true iff the strings are equal,
+     * or the apiType is generic and the test type is not void
+     */
+    private static boolean compareType(String apiType, String testType) {
+        return apiType.equals(testType) ||
+                isGenericType(apiType) && !testType.equals(VOID) ||
+                isGenericArrayType(apiType) && isArrayType(testType) ;
+    }
+
+    /**
+     * @return true iff the given parameterType is a generic type.
+     */
+    private static boolean isGenericType(String type) {
+        return type.length() == 1 &&
+                type.charAt(0) >= 'A' &&
+                type.charAt(0) <= 'Z';
+    }
+
+    /**
+     * @return true iff {@code type} ends with an [].
+     */
+    private static boolean isArrayType(String type) {
+        return type.endsWith("[]");
+    }
+
+    /**
+     * @return true iff the given parameterType is an array of generic type.
+     */
+    private static boolean isGenericArrayType(String type) {
+        return type.length() == 3 && isGenericType(type.substring(0, 1)) && isArrayType(type);
+    }
+
     private ApiConstructor getConstructor(List<String> parameterTypes) {
         for (ApiConstructor constructor : mApiConstructors) {
-            if (parameterTypes.equals(constructor.getParameterTypes())) {
+            if (compareParameterTypes(constructor.getParameterTypes(), parameterTypes)) {
                 return constructor;
             }
         }