improve method coverate analysis of CTS
- do not count interface / abstract class with only abstract methods
- do not count enums
- add total count (do not include deprecated)
Change-Id: Iaa8ce0bf84963d1819292fa8b1aaeada2a761731
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 101be7f..2a62aa0 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
@@ -28,13 +28,16 @@
private final boolean mDeprecated;
+ private final boolean mAbstract;
+
private final List<ApiConstructor> mApiConstructors = new ArrayList<ApiConstructor>();
private final List<ApiMethod> mApiMethods = new ArrayList<ApiMethod>();
- ApiClass(String name, boolean deprecated) {
+ ApiClass(String name, boolean deprecated, boolean classAbstract) {
mName = name;
mDeprecated = deprecated;
+ mAbstract = classAbstract;
}
@Override
@@ -51,6 +54,10 @@
return mDeprecated;
}
+ public boolean isAbstract() {
+ return mAbstract;
+ }
+
public void addConstructor(ApiConstructor constructor) {
mApiConstructors.add(constructor);
}
@@ -108,6 +115,10 @@
@Override
public float getCoveragePercentage() {
- return (float) getNumCoveredMethods() / getTotalMethods() * 100;
+ if (getTotalMethods() == 0) {
+ return 100;
+ } else {
+ return (float) getNumCoveredMethods() / getTotalMethods() * 100;
+ }
}
-}
\ No newline at end of file
+}
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 dc40062..adf2ea9 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
@@ -16,6 +16,7 @@
package com.android.cts.apicoverage;
+import java.lang.String;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -37,4 +38,11 @@
public Collection<ApiPackage> getPackages() {
return Collections.unmodifiableCollection(mPackages.values());
}
+
+ public void removeEmptyAbstractClasses() {
+ for (Map.Entry<String, ApiPackage> entry : mPackages.entrySet()) {
+ ApiPackage pkg = entry.getValue();
+ pkg.removeEmptyAbstractClasses();
+ }
+ }
}
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 ddc6fb4..c83256c 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
@@ -19,7 +19,9 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Map;
+import java.util.Map.Entry;
/** Representation of a package in the API containing classes. */
class ApiPackage implements HasCoverage {
@@ -69,4 +71,16 @@
public float getCoveragePercentage() {
return (float) getNumCoveredMethods() / getTotalMethods() * 100;
}
-}
\ No newline at end of file
+
+ public void removeEmptyAbstractClasses() {
+ 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();
+ }
+ }
+ }
+}
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 2923ba2..d6abf9a 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
@@ -109,6 +109,7 @@
*/
ApiCoverage apiCoverage = getEmptyApiCoverage(apiXmlPath);
+ apiCoverage.removeEmptyAbstractClasses();
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 f3abd86..b9f9e9c 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
@@ -32,12 +32,17 @@
private String mCurrentClassName;
+ private boolean mIgnoreCurrentClass;
+
private String mCurrentMethodName;
private String mCurrentMethodReturnType;
+ private boolean mCurrentMethodIsAbstract;
+
private boolean mDeprecated;
+
private List<String> mCurrentParameterTypes = new ArrayList<String>();
private ApiCoverage mApiCoverage = new ApiCoverage();
@@ -56,15 +61,20 @@
ApiPackage apiPackage = new ApiPackage(mCurrentPackageName);
mApiCoverage.addPackage(apiPackage);
- } else if ("class".equalsIgnoreCase(localName)
- || "interface".equalsIgnoreCase(localName)) {
+ } else if ("class".equalsIgnoreCase(localName)) {
+ if (isEnum(attributes)) {
+ mIgnoreCurrentClass = true;
+ return;
+ }
+ mIgnoreCurrentClass = false;
mCurrentClassName = getValue(attributes, "name");
mDeprecated = isDeprecated(attributes);
-
- ApiClass apiClass = new ApiClass(mCurrentClassName, mDeprecated);
+ ApiClass apiClass = new ApiClass(mCurrentClassName, mDeprecated, isAbstract(attributes));
ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
apiPackage.addClass(apiClass);
-
+ } else if ("interface".equalsIgnoreCase(localName)) {
+ // don't add interface
+ mIgnoreCurrentClass = true;
} else if ("constructor".equalsIgnoreCase(localName)) {
mDeprecated = isDeprecated(attributes);
mCurrentParameterTypes.clear();
@@ -72,6 +82,7 @@
mDeprecated = isDeprecated(attributes);
mCurrentMethodName = getValue(attributes, "name");
mCurrentMethodReturnType = getValue(attributes, "return");
+ mCurrentMethodIsAbstract = isAbstract(attributes);
mCurrentParameterTypes.clear();
} else if ("parameter".equalsIgnoreCase(localName)) {
mCurrentParameterTypes.add(getValue(attributes, "type"));
@@ -81,6 +92,10 @@
@Override
public void endElement(String uri, String localName, String name) throws SAXException {
super.endElement(uri, localName, name);
+ if (mIgnoreCurrentClass) {
+ // do not add anything for interface
+ return;
+ }
if ("constructor".equalsIgnoreCase(localName)) {
if (mCurrentParameterTypes.isEmpty()) {
// Don't add empty default constructors...
@@ -92,6 +107,9 @@
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);
ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
@@ -110,4 +128,12 @@
private boolean isDeprecated(Attributes attributes) {
return "deprecated".equals(attributes.getValue("deprecated"));
}
+
+ private boolean isAbstract(Attributes attributes) {
+ return "true".equals(attributes.getValue("abstract"));
+ }
+
+ private boolean isEnum(Attributes attributes) {
+ return "java.lang.Enum".equals(attributes.getValue("extends"));
+ }
}
\ No newline at end of file
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 94ccbb4..e76343e 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
@@ -54,12 +54,18 @@
CoverageComparator comparator = new CoverageComparator();
List<ApiPackage> packages = new ArrayList<ApiPackage>(apiCoverage.getPackages());
Collections.sort(packages, comparator);
+ int totalMethods = 0;
+ int totalCoveredMethods = 0;
for (ApiPackage pkg : packages) {
if (pkg.getName().startsWith("android")
&& pkg.getTotalMethods() > 0) {
+ int pkgTotal = pkg.getTotalMethods();
+ totalMethods += pkgTotal;
+ int pkgTotalCovered = pkg.getNumCoveredMethods();
+ totalCoveredMethods += pkgTotalCovered;
out.println("<package name=\"" + pkg.getName()
- + "\" numCovered=\"" + pkg.getNumCoveredMethods()
- + "\" numTotal=\"" + pkg.getTotalMethods()
+ + "\" numCovered=\"" + pkgTotalCovered
+ + "\" numTotal=\"" + pkgTotal
+ "\" coveragePercentage=\""
+ Math.round(pkg.getCoveragePercentage())
+ "\">");
@@ -81,7 +87,12 @@
out.println("<constructor name=\"" + constructor.getName()
+ "\" deprecated=\"" + constructor.isDeprecated()
+ "\" covered=\"" + constructor.isCovered() + "\">");
-
+ if (constructor.isDeprecated()) {
+ if (constructor.isCovered()) {
+ totalCoveredMethods -= 1;
+ }
+ totalMethods -= 1;
+ }
for (String parameterType : constructor.getParameterTypes()) {
out.println("<parameter type=\"" + parameterType + "\" />");
}
@@ -94,7 +105,12 @@
+ "\" returnType=\"" + method.getReturnType()
+ "\" deprecated=\"" + method.isDeprecated()
+ "\" covered=\"" + method.isCovered() + "\">");
-
+ if (method.isDeprecated()) {
+ if (method.isCovered()) {
+ totalCoveredMethods -= 1;
+ }
+ totalMethods -= 1;
+ }
for (String parameterType : method.getParameterTypes()) {
out.println("<parameter type=\"" + parameterType + "\" />");
}
@@ -109,6 +125,10 @@
}
out.println("</api>");
+ out.println("<total numCovered=\"" + totalCoveredMethods + "\" "
+ + "numTotal=\"" + totalMethods + "\" "
+ + "coveragePercentage=\""
+ + Math.round((float)totalCoveredMethods / totalMethods * 100.0f) + "\" />");
out.println("</api-coverage>");
}
}
diff --git a/tools/cts-api-coverage/src/res/api-coverage.xsl b/tools/cts-api-coverage/src/res/api-coverage.xsl
index 95994e2..9cd4aeb 100644
--- a/tools/cts-api-coverage/src/res/api-coverage.xsl
+++ b/tools/cts-api-coverage/src/res/api-coverage.xsl
@@ -82,6 +82,10 @@
<div class="info">
Generated: <xsl:value-of select="api-coverage/@generatedTime" />
</div>
+ <div class="total">
+ Total: <xsl:value-of select="api-coverage/total/@coveragePercentage" />%
+ (<xsl:value-of select="api-coverage/total/@numCovered" />/<xsl:value-of select="api-coverage/total/@numTotal" />)
+ </div>
<div class="apks" onclick="toggleVisibility('sourceApks')">
Source APKs (<xsl:value-of select="count(api-coverage/debug/sources/apk)" />)
</div>