Various updates to CTS coverage tool
-Report coverage of superclass methods.
e.g. MidiSender.connect is now covered
-Show coverage of abstract methods.
e.g. android.hardware.camera2.CameraDevice is now covered
-Display method visibility, if static and if final
-Fix a bug in the xsl that prevented toggling visibility on
classes with a class name duplicated elswhere in the codebase
bug: 19272826
Change-Id: I2c4b97a3367f51b7a9fe637a570b6d881a428c0e
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 31e1f8d..f5abd5e5 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
@@ -34,10 +34,25 @@
private final List<ApiMethod> mApiMethods = new ArrayList<ApiMethod>();
- ApiClass(String name, boolean deprecated, boolean classAbstract) {
+ private final String mSuperClassName;
+
+ private ApiClass mSuperClass;
+
+ /**
+ * @param name The name of the class
+ * @param deprecated true iff the class is marked as deprecated
+ * @param classAbstract true iff the class is abstract
+ * @param superClassName The fully qualified name of the super class
+ */
+ ApiClass(
+ String name,
+ boolean deprecated,
+ boolean classAbstract,
+ String superClassName) {
mName = name;
mDeprecated = deprecated;
mAbstract = classAbstract;
+ mSuperClassName = superClassName;
}
@Override
@@ -54,22 +69,20 @@
return mDeprecated;
}
+ public String getSuperClassName() {
+ return mSuperClassName;
+ }
+
public boolean isAbstract() {
return mAbstract;
}
+ public void setSuperClass(ApiClass superClass) { mSuperClass = superClass; }
+
public void addConstructor(ApiConstructor constructor) {
mApiConstructors.add(constructor);
}
- public ApiConstructor getConstructor(List<String> parameterTypes) {
- for (ApiConstructor constructor : mApiConstructors) {
- if (parameterTypes.equals(constructor.getParameterTypes())) {
- return constructor;
- }
- }
- return null;
- }
public Collection<ApiConstructor> getConstructors() {
return Collections.unmodifiableList(mApiConstructors);
@@ -79,15 +92,29 @@
mApiMethods.add(method);
}
- public 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())) {
- return method;
- }
+ /** Look for a matching constructor and mark it as covered */
+ public void markConstructorCovered(List<String> parameterTypes) {
+ if (mSuperClass != null) {
+ // Mark matching constructors in the superclass
+ mSuperClass.markConstructorCovered(parameterTypes);
}
- return null;
+ ApiConstructor apiConstructor = getConstructor(parameterTypes);
+ if (apiConstructor != null) {
+ apiConstructor.setCovered(true);
+ }
+
+ }
+
+ /** Look for a matching method and if found and mark it as covered */
+ public void markMethodCovered(String name, List<String> parameterTypes, String returnType) {
+ if (mSuperClass != null) {
+ // Mark matching methods in the super class
+ mSuperClass.markMethodCovered(name, parameterTypes, returnType);
+ }
+ ApiMethod apiMethod = getMethod(name, parameterTypes, returnType);
+ if (apiMethod != null) {
+ apiMethod.setCovered(true);
+ }
}
public Collection<ApiMethod> getMethods() {
@@ -126,4 +153,24 @@
public int getMemberSize() {
return getTotalMethods();
}
+
+ 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())) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ private ApiConstructor getConstructor(List<String> parameterTypes) {
+ for (ApiConstructor constructor : mApiConstructors) {
+ if (parameterTypes.equals(constructor.getParameterTypes())) {
+ return constructor;
+ }
+ }
+ return null;
+ }
}
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiCoverage.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiCoverage.java
index adf2ea9..953aab3 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiCoverage.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiCoverage.java
@@ -39,10 +39,11 @@
return Collections.unmodifiableCollection(mPackages.values());
}
- public void removeEmptyAbstractClasses() {
+ /** Iterate through all packages and update all classes to include its superclass */
+ public void resolveSuperClasses() {
for (Map.Entry<String, ApiPackage> entry : mPackages.entrySet()) {
ApiPackage pkg = entry.getValue();
- pkg.removeEmptyAbstractClasses();
+ pkg.resolveSuperClasses(mPackages);
}
}
}
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiMethod.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiMethod.java
index 053cd12..582c2b6 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiMethod.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiMethod.java
@@ -29,15 +29,35 @@
private final String mReturnType;
- private boolean mDeprecated;
+ private final boolean mDeprecated;
+
+ private final String mVisibility;
+
+ private final boolean mStaticMethod;
+
+ private final boolean mFinalMethod;
+
+ private final boolean mAbstractMethod;
private boolean mIsCovered;
- ApiMethod(String name, List<String> parameterTypes, String returnType, boolean deprecated) {
+ ApiMethod(
+ String name,
+ List<String> parameterTypes,
+ String returnType,
+ boolean deprecated,
+ String visibility,
+ boolean staticMethod,
+ boolean finalMethod,
+ boolean abstractMethod) {
mName = name;
mParameterTypes = new ArrayList<String>(parameterTypes);
mReturnType = returnType;
mDeprecated = deprecated;
+ mVisibility = visibility;
+ mStaticMethod = staticMethod;
+ mFinalMethod = finalMethod;
+ mAbstractMethod = abstractMethod;
}
@Override
@@ -65,6 +85,14 @@
return mIsCovered;
}
+ public String getVisibility() { return mVisibility; }
+
+ public boolean isAbstractMethod() { return mAbstractMethod; }
+
+ public boolean isStaticMethod() { return mStaticMethod; }
+
+ public boolean isFinalMethod() { return mFinalMethod; }
+
public void setCovered(boolean covered) {
mIsCovered = covered;
}
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java
index e0bf73f..7be7e3c 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/ApiPackage.java
@@ -77,14 +77,26 @@
return getTotalMethods();
}
- public void removeEmptyAbstractClasses() {
+ /** Iterate through all classes and add superclass. */
+ public void resolveSuperClasses(Map<String, ApiPackage> packageMap) {
Iterator<Entry<String, ApiClass>> it = mApiClassMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, ApiClass> entry = it.next();
- ApiClass cls = entry.getValue();
- if (cls.isAbstract() && (cls.getTotalMethods() == 0)) {
- // this is essentially interface
- it.remove();
+ ApiClass apiClass = entry.getValue();
+ if (apiClass.getSuperClassName() != null) {
+ String superClassName = apiClass.getSuperClassName();
+ // Split the fully qualified class name into package and class name.
+ String packageName = superClassName.substring(0, superClassName.lastIndexOf('.'));
+ String className = superClassName.substring(
+ superClassName.lastIndexOf('.') + 1, superClassName.length());
+ if (packageMap.containsKey(packageName)) {
+ ApiPackage apiPackage = packageMap.get(packageName);
+ ApiClass superClass = apiPackage.getClass(className);
+ if (superClass != null) {
+ // Add the super class
+ apiClass.setSuperClass(superClass);
+ }
+ }
}
}
}
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java
index 05cb4e19..3f2f353 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CtsApiCoverage.java
@@ -117,7 +117,8 @@
*/
ApiCoverage apiCoverage = getEmptyApiCoverage(apiXmlPath);
- apiCoverage.removeEmptyAbstractClasses();
+ // Add superclass information into api coverage.
+ apiCoverage.resolveSuperClasses();
for (File testApk : testApks) {
addApiCoverage(apiCoverage, testApk, dexDeps);
}
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java
index b9f9e9c..de9f5d5 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/CurrentXmlHandler.java
@@ -40,6 +40,12 @@
private boolean mCurrentMethodIsAbstract;
+ private String mCurrentMethodVisibility;
+
+ private boolean mCurrentMethodStaticMethod;
+
+ private boolean mCurrentMethodFinalMethod;
+
private boolean mDeprecated;
@@ -69,7 +75,9 @@
mIgnoreCurrentClass = false;
mCurrentClassName = getValue(attributes, "name");
mDeprecated = isDeprecated(attributes);
- ApiClass apiClass = new ApiClass(mCurrentClassName, mDeprecated, isAbstract(attributes));
+ String superClass = attributes.getValue("extends");
+ ApiClass apiClass = new ApiClass(
+ mCurrentClassName, mDeprecated, is(attributes, "abstract"), superClass);
ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
apiPackage.addClass(apiClass);
} else if ("interface".equalsIgnoreCase(localName)) {
@@ -82,7 +90,10 @@
mDeprecated = isDeprecated(attributes);
mCurrentMethodName = getValue(attributes, "name");
mCurrentMethodReturnType = getValue(attributes, "return");
- mCurrentMethodIsAbstract = isAbstract(attributes);
+ mCurrentMethodIsAbstract = is(attributes, "abstract");
+ mCurrentMethodVisibility = getValue(attributes, "visibility");
+ mCurrentMethodStaticMethod = is(attributes, "static");
+ mCurrentMethodFinalMethod = is(attributes, "final");
mCurrentParameterTypes.clear();
} else if ("parameter".equalsIgnoreCase(localName)) {
mCurrentParameterTypes.add(getValue(attributes, "type"));
@@ -107,11 +118,15 @@
ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
apiClass.addConstructor(apiConstructor);
} else if ("method".equalsIgnoreCase(localName)) {
- if (mCurrentMethodIsAbstract) { // do not add abstract method
- return;
- }
- ApiMethod apiMethod = new ApiMethod(mCurrentMethodName, mCurrentParameterTypes,
- mCurrentMethodReturnType, mDeprecated);
+ ApiMethod apiMethod = new ApiMethod(
+ mCurrentMethodName,
+ mCurrentParameterTypes,
+ mCurrentMethodReturnType,
+ mDeprecated,
+ mCurrentMethodVisibility,
+ mCurrentMethodStaticMethod,
+ mCurrentMethodFinalMethod,
+ mCurrentMethodIsAbstract);
ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
apiClass.addMethod(apiMethod);
@@ -129,8 +144,8 @@
return "deprecated".equals(attributes.getValue("deprecated"));
}
- private boolean isAbstract(Attributes attributes) {
- return "true".equals(attributes.getValue("abstract"));
+ private static boolean is(Attributes attributes, String valueName) {
+ return "true".equals(attributes.getValue(valueName));
}
private boolean isEnum(Attributes attributes) {
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/DexDepsXmlHandler.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/DexDepsXmlHandler.java
index 0a90bdd..3df532e 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/DexDepsXmlHandler.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/DexDepsXmlHandler.java
@@ -73,10 +73,7 @@
if (apiPackage != null) {
ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
if (apiClass != null) {
- ApiConstructor apiConstructor = apiClass.getConstructor(mCurrentParameterTypes);
- if (apiConstructor != null) {
- apiConstructor.setCovered(true);
- }
+ apiClass.markConstructorCovered(mCurrentParameterTypes);
}
}
} else if ("method".equalsIgnoreCase(localName)) {
@@ -84,11 +81,8 @@
if (apiPackage != null) {
ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
if (apiClass != null) {
- ApiMethod apiMethod = apiClass.getMethod(mCurrentMethodName,
- mCurrentParameterTypes, mCurrentMethodReturnType);
- if (apiMethod != null) {
- apiMethod.setCovered(true);
- }
+ apiClass.markMethodCovered(
+ mCurrentMethodName, mCurrentParameterTypes, mCurrentMethodReturnType);
}
}
}
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/TextReport.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/TextReport.java
index e3e2e7c..3adc020 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/TextReport.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/TextReport.java
@@ -103,7 +103,18 @@
private static void printMethod(ApiMethod method, PrintStream out) {
StringBuilder builder = new StringBuilder(" [")
.append(method.isCovered() ? "X" : " ")
- .append("] ").append(method.getReturnType()).append(" ")
+ .append("] ")
+ .append(method.getVisibility()).append(" ");
+ if (method.isAbstractMethod()) {
+ builder.append("abstract ");
+ }
+ if (method.isStaticMethod()) {
+ builder.append("static ");
+ }
+ if (method.isFinalMethod()) {
+ builder.append("final ");
+ }
+ builder.append(method.getReturnType()).append(" ")
.append(method.getName()).append("(");
List<String> parameterTypes = method.getParameterTypes();
int numParameterTypes = parameterTypes.size();
diff --git a/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java b/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java
index 570b316..4310d20 100644
--- a/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java
+++ b/tools/cts-api-coverage/src/com/android/cts/apicoverage/XmlReport.java
@@ -66,7 +66,7 @@
+ "\" numCovered=\"" + pkgTotalCovered
+ "\" numTotal=\"" + pkgTotal
+ "\" coveragePercentage=\""
- + Math.round(pkg.getCoveragePercentage())
+ + Math.round(pkg.getCoveragePercentage())
+ "\">");
List<ApiClass> classes = new ArrayList<ApiClass>(pkg.getClasses());
@@ -103,6 +103,10 @@
out.println("<method name=\"" + method.getName()
+ "\" returnType=\"" + method.getReturnType()
+ "\" deprecated=\"" + method.isDeprecated()
+ + "\" static=\"" + method.isStaticMethod()
+ + "\" final=\"" + method.isFinalMethod()
+ + "\" visibility=\"" + method.getVisibility()
+ + "\" abstract=\"" + method.isAbstractMethod()
+ "\" covered=\"" + method.isCovered() + "\">");
if (method.isDeprecated()) {
if (method.isCovered()) {
diff --git a/tools/cts-api-coverage/src/res/api-coverage.xsl b/tools/cts-api-coverage/src/res/api-coverage.xsl
index b11a8c4..1a56eb0 100644
--- a/tools/cts-api-coverage/src/res/api-coverage.xsl
+++ b/tools/cts-api-coverage/src/res/api-coverage.xsl
@@ -101,14 +101,17 @@
<xsl:for-each select="api-coverage/api/package">
<xsl:call-template name="packageOrClassListItem">
<xsl:with-param name="bulletClass" select="'package'" />
+ <xsl:with-param name="toggleId" select="@name" />
</xsl:call-template>
<div class="packageDetails" id="{@name}" style="display: none">
<ul>
<xsl:for-each select="class">
+ <xsl:variable name="packageClassId" select="concat(../@name, '.', @name)"/>
<xsl:call-template name="packageOrClassListItem">
<xsl:with-param name="bulletClass" select="'class'" />
+ <xsl:with-param name="toggleId" select="$packageClassId" />
</xsl:call-template>
- <div class="classDetails" id="{@name}" style="display: none">
+ <div class="classDetails" id="{$packageClassId}" style="display: none">
<xsl:for-each select="constructor">
<xsl:call-template name="methodListItem" />
</xsl:for-each>
@@ -124,9 +127,10 @@
</body>
</html>
</xsl:template>
-
+
<xsl:template name="packageOrClassListItem">
<xsl:param name="bulletClass" />
+ <xsl:param name="toggleId"/>
<xsl:variable name="colorClass">
<xsl:choose>
@@ -135,7 +139,7 @@
<xsl:otherwise>green</xsl:otherwise>
</xsl:choose>
</xsl:variable>
-
+
<xsl:variable name="deprecatedClass">
<xsl:choose>
<xsl:when test="@deprecated = 'true'">deprecated</xsl:when>
@@ -143,15 +147,15 @@
</xsl:choose>
</xsl:variable>
- <li class="{$bulletClass}" onclick="toggleVisibility('{@name}')">
+ <li class="{$bulletClass}" onclick="toggleVisibility('{$toggleId}')">
<span class="{$colorClass} {$deprecatedClass}">
<b><xsl:value-of select="@name" /></b>
<xsl:value-of select="@coveragePercentage" />%
(<xsl:value-of select="@numCovered" />/<xsl:value-of select="@numTotal" />)
</span>
- </li>
+ </li>
</xsl:template>
-
+
<xsl:template name="methodListItem">
<xsl:variable name="deprecatedClass">
@@ -166,6 +170,10 @@
<xsl:when test="@covered = 'true'">[X]</xsl:when>
<xsl:otherwise>[ ]</xsl:otherwise>
</xsl:choose>
+ <xsl:if test="@visibility != ''"> <xsl:value-of select="@visibility" /></xsl:if>
+ <xsl:if test="@abstract = 'true'"> abstract</xsl:if>
+ <xsl:if test="@static = 'true'"> static</xsl:if>
+ <xsl:if test="@final = 'true'"> final</xsl:if>
<xsl:if test="@returnType != ''"> <xsl:value-of select="@returnType" /></xsl:if>
<b> <xsl:value-of select="@name" /></b><xsl:call-template name="formatParameters" />
</span>