Mercurial > hg > MauveTestCoverage
changeset 14:eec2474fdaaa
* src/ClassInfo.java:
Added new helper class.
* src/FileUtils.java:
Added new method for reading contents of text file.
Refactored.
* src/ReportGenerator.java:
New functionality: methods coverage are printed
in package list (previously only class coverage
were printed).
Refactored.
* templates/all_packages_template.html:
* templates/index.html:
Changed width of left column.
* templates/style.css:
Tables have black borders (they are more visible).
* Makefile:
Updated according to previous changes.
author | Pavel Tisnovsky <ptisnovs@redhat.com> |
---|---|
date | Fri, 23 Mar 2012 11:55:40 +0100 |
parents | 8c9c61f17fd1 |
children | ed99188fff20 |
files | ChangeLog Makefile src/ClassInfo.java src/FileUtils.java src/ReportGenerator.java templates/all_packages_template.html templates/index.html templates/style.css |
diffstat | 8 files changed, 302 insertions(+), 104 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Fri Mar 16 11:24:48 2012 +0100 +++ b/ChangeLog Fri Mar 23 11:55:40 2012 +0100 @@ -1,3 +1,23 @@ +2012-03-23 Pavel Tisnovsky <ptisnovs@redhat.com> + + * src/ClassInfo.java: + Added new helper class. + * src/FileUtils.java: + Added new method for reading contents of text file. + Refactored. + * src/ReportGenerator.java: + New functionality: methods coverage are printed + in package list (previously only class coverage + were printed). + Refactored. + * templates/all_packages_template.html: + * templates/index.html: + Changed width of left column. + * templates/style.css: + Tables have black borders (they are more visible). + * Makefile: + Updated according to previous changes. + 2012-03-16 Pavel Tisnovsky <ptisnovs@redhat.com> * src/ReportGenerator.java:
--- a/Makefile Fri Mar 16 11:24:48 2012 +0100 +++ b/Makefile Fri Mar 23 11:55:40 2012 +0100 @@ -74,7 +74,8 @@ $(CLASSDIR)/PrintPublicMethods.class \ $(CLASSDIR)/PrintTestCoverage.class \ $(CLASSDIR)/ReportGenerator.class \ - $(CLASSDIR)/FileUtils.class + $(CLASSDIR)/FileUtils.class \ + $(CLASSDIR)/ClassInfo.class api_class_list: $(REPORTDIR) $(REPORTDIR)/$(ALL_CLASS_LIST)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ClassInfo.java Fri Mar 23 11:55:40 2012 +0100 @@ -0,0 +1,176 @@ +/* + Test coverage tool. + + Copyright (C) 2012 Red Hat + +This tool is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This tool is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this tool; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. +*/ + +import java.io.File; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + + + +/** + * Instances of this class contain information about one tested class. + * There are three sets of strings stored for each class: set of methods + * contained in standard API, set of methods called from tests and the + * union of previous two sets. These information are used by test reporter. + * + * @author Pavel Tisnovsky <ptisnovs@redhat.com> + */ +public class ClassInfo +{ + /** + * Set of methods contained in standard API. + */ + private Set<String> apiMethods; + + /** + * Set of methods called from tests. + */ + private Set<String> testedMethods; + + /** + * Union of apiMethods and testedMethods. + */ + private Set<String> allMethods; + + /** + * Constructor. It tries to read all required information + * for tested class. + * + * @param reportDirectory + * directory where all reports are stored + * @param className + * name of tested class + */ + public ClassInfo(String reportDirectory, String className) + { + // read methods described in standard API + this.apiMethods = readApiMethods(reportDirectory, className); + // read methods called from tests + this.testedMethods = readTestedMethods(reportDirectory, className); + // compute union of previous two sets + computeAllMethodsSet(); + } + + /** + * Compute union of allMethods and testedMethods sets. + */ + private void computeAllMethodsSet() + { + this.allMethods = new TreeSet<String>(); + this.allMethods.addAll(this.apiMethods); + this.allMethods.addAll(this.testedMethods); + } + + /** + * Getter for a set apiMethods. + * + * @return the apiMethods attribute + */ + public Set<String> getApiMethods() + { + return this.apiMethods; + } + + /** + * Getter for a set testedMethods. + * + * @return the testedMethods attribute + */ + public Set<String> getTestedMethods() + { + return this.testedMethods; + } + + /** + * Getter for a set allMethods. + * + * @return the allMethods attribute + */ + public Set<String> getAllMethods() + { + return this.allMethods; + } + + /** + * Read all methods for a given class which are covered by a standard API. + * + * @param reportDirectory + * directory where all reports are stored + * @param testedClass + * name of tested class + * @return set of all methods read from a file containing standard API + */ + private static Set<String> readApiMethods(String reportDirectory, String testedClass) + { + File fileName = new File(reportDirectory, testedClass + "_api.txt"); + return readMethods(fileName); + } + + /** + * Read all methods for a given class which are called from tests. + * + * @param reportDirectory + * directory where all reports are stored + * @param testedClass + * name of tested class + * @return set of all methods read from a file containing called methods + */ + private static Set<String> readTestedMethods(String reportDirectory, String testedClass) + { + File fileName = new File(reportDirectory, testedClass + "_test.txt"); + return readMethods(fileName); + } + + /** + * Read set of method names from a text file. No exception is thrown during + * reading. + * + * @param fileName + * file containing methods list + * @return set of method names + */ + private static Set<String> readMethods(File fileName) + { + Set<String> allMethods = new TreeSet<String>(); + List<String> methodList = FileUtils.readTextFile(fileName.getAbsolutePath(), false); + allMethods.addAll(methodList); + return allMethods; + } + +}
--- a/src/FileUtils.java Fri Mar 16 11:24:48 2012 +0100 +++ b/src/FileUtils.java Fri Mar 23 11:55:40 2012 +0100 @@ -46,6 +46,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; +import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -76,6 +77,21 @@ */ static List<String> readTextFile(String fileName) { + return readTextFile(fileName, true); + } + + /** + * Read content of given text file and return it as list of strings. No + * exception is thrown during reading. + * + * @param fileName + * name of file to be read + * @param printFileNotFoundException + * whether to print an exception when file is not found + * @return list of string containing content of text file + */ + static List<String> readTextFile(String fileName, boolean printFileNotFoundException) + { BufferedReader reader = null; List<String> out = new LinkedList<String>(); try @@ -87,7 +103,12 @@ catch (FileNotFoundException e) { // might happen - empty list is returned in this case - e.printStackTrace(); + if (printFileNotFoundException) + { + // in some cases we don't want to see this exception + // (because some classes, for example, could not be tested at all) + e.printStackTrace(); + } } catch (IOException e) { @@ -215,7 +236,7 @@ * @throws IOException * thrown if an I/O error occurs */ - private static void readAllLinesFromTextFile(BufferedReader bufferedReader, List<String> lines) throws IOException + private static void readAllLinesFromTextFile(BufferedReader bufferedReader, Collection<String> lines) throws IOException { String line; // read lines from a text file
--- a/src/ReportGenerator.java Fri Mar 16 11:24:48 2012 +0100 +++ b/src/ReportGenerator.java Fri Mar 23 11:55:40 2012 +0100 @@ -36,14 +36,10 @@ exception statement from your version. */ -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeSet; @@ -58,11 +54,6 @@ public class ReportGenerator { /** - * Default charset used during all input/output operations. - */ - private static final String DEFAULT_CHARSET = "UTF-8"; - - /** * Location of internal or external URI to standard API JavaDoc */ private static final String DOC_BASE = "http://docs.oracle.com/javase/6/docs/api"; @@ -97,9 +88,10 @@ * set of tested classes * @param packageNames * set of package names + * @param classInfoMap */ private static void printPackageListToFile(String reportDirectory, Set<String> allClasses, - Set<String> testedClasses, Set<String> packageNames) + Set<String> testedClasses, Set<String> packageNames, Map<String, ClassInfo> classInfoMap) { List<String> template = FileUtils.readTextFile("templates/all_packages_template.html"); List<String> out = new LinkedList<String>(); @@ -109,7 +101,7 @@ // replace text in template where needed if ("${PACKAGE_LIST}".equals(templateLine)) { - addPackageList(allClasses, testedClasses, packageNames, out); + addPackageList(allClasses, testedClasses, packageNames, out, classInfoMap); } // normal line else @@ -132,9 +124,10 @@ * package for which the report is generated * @param testedClasses * set of tested classes + * @param classInfoMap */ private static void printReportForPackageToFile(String reportDirectory, String packageName, - Set<String> testedClasses) + Set<String> testedClasses, Map<String, ClassInfo> classInfoMap) { // read HTML template List<String> template = FileUtils.readTextFile("templates/package_template.html"); @@ -146,7 +139,7 @@ // replace text in template where needed if ("${CLASS_LIST}".equals(templateLine)) { - addClassList(reportDirectory, packageName, testedClasses, out); + addClassList(reportDirectory, packageName, testedClasses, out, classInfoMap); } else if ("${PACKAGE_NAME}".equals(templateLine)) { @@ -173,9 +166,10 @@ * all checked package names * @param testedClasses * set of tested classes + * @param classInfoMap */ private static void printReportForAllClassesInOneFile(String reportDirectory, Set<String> usedPackageNames, - Set<String> testedClasses) + Set<String> testedClasses, Map<String, ClassInfo> classInfoMap) { List<String> template = FileUtils.readTextFile("templates/all_classes_template.html"); List<String> out = new LinkedList<String>(); @@ -185,7 +179,7 @@ // replace text in template where needed if ("${PACKAGE_AND_CLASS_LIST}".equals(templateLine)) { - addPackageAndClassList(reportDirectory, usedPackageNames, testedClasses, out); + addPackageAndClassList(reportDirectory, usedPackageNames, testedClasses, out, classInfoMap); } // normal line else @@ -214,25 +208,52 @@ */ @SuppressWarnings("boxing") private static void addPackageList(Set<String> allClasses, Set<String> testedClasses, Set<String> packageNames, - List<String> out) + List<String> out, Map<String, ClassInfo> classInfoMap) { // iterate through all package names for (String packageName : packageNames) { // compute number of all classes in a package final int allClassesCnt = numberOfClassesInPackage(packageName, allClasses); - // compute number of classes coveraged by tests + // compute number of classes covered by tests final int testedClassesCnt = numberOfClassesInPackage(packageName, testedClasses); // -> in percent - final float percentage = 100.0f*testedClassesCnt / allClassesCnt; + final float classPercentage = allClassesCnt == 0 ? 0.0f : 100.0f * testedClassesCnt / allClassesCnt; + // table row background color is based on percentual test coverage ration + String backgroundColor1 = generateTableRowBackground(classPercentage); + int allMethodsCnt=0; + int coveragedMethodsCnt=0; + for (String className : allClasses) + { + // count only classes in given package + if (className.startsWith(packageName)) + { + ClassInfo classInfo = classInfoMap.get(className); + allMethodsCnt += classInfo.getAllMethods().size(); + coveragedMethodsCnt += classInfo.getTestedMethods().size(); + } + } + float methodsPercentage = allMethodsCnt == 0 ? 0.0f : 100.0f * coveragedMethodsCnt / allMethodsCnt; // table row background color is based on percentual test coverage ration - String backgroundColor = generateTableRowBackground(percentage); + String backgroundColor2 = generateTableRowBackground(methodsPercentage); + + // format output string String doc = DOC_BASE + "/" + packageName.replace('.', '/') + "/package-summary.html"; - // format output string - String str = String.format("<tr style='background-color:%s'><td><a target='ClassesListFrame' href='%s.html'>%s</a></td><td style='text-align:right'>%d</td><td style='text-align:right'>%d</td><td style='text-align:right'>%5.1f %%</td><td style='text-align:right'><a href='%s' target='_blank'>ext</a></td></tr>", - backgroundColor, packageName, packageName, - allClassesCnt, testedClassesCnt, percentage, doc); + + String str = String.format( + "<tr><td><a target='ClassesListFrame' href='%s.html'>%s</a></td>" + + "<td style='background-color:%s;text-align:right'>%d</td>" + + "<td style='background-color:%s;text-align:right'>%d</td>" + + "<td style='background-color:%s;text-align:right'>%5.1f %%</td>" + + "<td style='background-color:%s;text-align:right'>%d</td>" + + "<td style='background-color:%s;text-align:right'>%d</td>" + + "<td style='background-color:%s;text-align:right'>%5.1f %%</td>" + + "<td style='text-align:right'><a href='%s' target='_blank'>ext</a></td></tr>", + packageName, packageName, + backgroundColor1, allClassesCnt, backgroundColor1, testedClassesCnt, backgroundColor1, classPercentage, + backgroundColor2, allMethodsCnt, backgroundColor2, coveragedMethodsCnt, backgroundColor2, methodsPercentage, + doc); out.add(str); } } @@ -270,7 +291,7 @@ for (String className : classes) { // count only classes in given package - if (className.startsWith(packageName)) + if (className.substring(0, className.lastIndexOf('.')).equals(packageName)) { cnt++; } @@ -288,8 +309,9 @@ * set of tested classes * @param out * list of string which represents generated report + * @param classInfoMap */ - private static void addClassList(String reportDirectory, String packageName, Set<String> testedClasses, List<String> out) + private static void addClassList(String reportDirectory, String packageName, Set<String> testedClasses, List<String> out, Map<String, ClassInfo> classInfoMap) { // iterate through all class names for (String className : testedClasses) @@ -298,7 +320,7 @@ if (className.startsWith(packageName)) { //out.add("<a target='ResultsFrame' href='" + className + ".html'>" + className + "</a><br>"); - out.add(addOneRowToResultsTable(reportDirectory, className)); + out.add(addOneRowToResultsTable(reportDirectory, className, classInfoMap)); } } } @@ -315,8 +337,9 @@ * set of tested classes * @param out * list of string which represents generated report + * @param classInfoMap */ - private static void addPackageAndClassList(String reportDirectory, Set<String> usedPackageNames, Set<String> testedClasses, List<String> out) + private static void addPackageAndClassList(String reportDirectory, Set<String> usedPackageNames, Set<String> testedClasses, List<String> out, Map<String, ClassInfo> classInfoMap) { // iterate through all class names for (String packageName : usedPackageNames) @@ -329,7 +352,7 @@ { if (className.startsWith(packageName)) { - out.add(addOneRowToResultsTable(reportDirectory, className)); + out.add(addOneRowToResultsTable(reportDirectory, className, classInfoMap)); } } out.add("</table>"); @@ -344,10 +367,10 @@ * @param className * name of tested class */ - private static String addOneRowToResultsTable(String reportDirectory, String className) + private static String addOneRowToResultsTable(String reportDirectory, String className, Map<String, ClassInfo> classInfoMap) { - Set<String> apiMethods = readApiMethods(reportDirectory, className); - Set<String> testedMethods = readTestedMethods(reportDirectory, className); + Set<String> apiMethods = classInfoMap.get(className).getApiMethods(); + Set<String> testedMethods = classInfoMap.get(className).getTestedMethods(); // compute number of all methods in a class final int allMethodsCnt = apiMethods.size(); // compute number of methods covered by tests @@ -515,81 +538,31 @@ * packages for which the report is generated * @param testedClasses * set of tested classes + * @param classInfoMap */ private static void printReportForAllPackages(String reportDirectory, Set<String> usedPackageNames, - Set<String> testedClasses) + Set<String> testedClasses, Map<String, ClassInfo> classInfoMap) { // iterate through all tested package names for (String packageName : usedPackageNames) { - printReportForPackageToFile(reportDirectory, packageName, testedClasses); + printReportForPackageToFile(reportDirectory, packageName, testedClasses, classInfoMap); } } - private static void printReportForAllClasses(String reportDirectory, Set<String> testedClasses) + private static void printReportForAllClasses(String reportDirectory, Set<String> testedClasses, Map<String, ClassInfo> classInfoMap)//String reportDirectory, Set<String> testedClasses) { // iterate through all tested classes for (String testedClass : testedClasses) { - Set<String> apiMethods = readApiMethods(reportDirectory, testedClass); - Set<String> testedMethods = readTestedMethods(reportDirectory, testedClass); - Set<String> allMethods = new TreeSet<String>(); - allMethods.addAll(apiMethods); - allMethods.addAll(testedMethods); + ClassInfo classInfo = classInfoMap.get(testedClass); + Set<String> apiMethods = classInfo.getApiMethods(); + Set<String> testedMethods = classInfo.getTestedMethods(); + Set<String> allMethods = classInfo.getAllMethods(); createFileForClass(reportDirectory, testedClass, allMethods, apiMethods, testedMethods); } } - private static Set<String> readApiMethods(String reportDirectory, String testedClass) - { - File fileName = new File(reportDirectory, testedClass + "_api.txt"); - return readMethods(fileName); - } - - private static Set<String> readTestedMethods(String reportDirectory, String testedClass) - { - File fileName = new File(reportDirectory, testedClass + "_test.txt"); - return readMethods(fileName); - } - - private static Set<String> readMethods(File fileName) - { - BufferedReader reader = null; - Set<String> allMethods = new TreeSet<String>(); - try - { - reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), DEFAULT_CHARSET)); - String line; - while ((line = reader.readLine()) != null) - { - allMethods.add(line); - } - } - catch (FileNotFoundException e) - { - e.printStackTrace(); - } - catch (IOException e) - { - e.printStackTrace(); - } - finally - { - try - { - if (reader != null) - { - reader.close(); - } - } - catch (IOException e) - { - e.printStackTrace(); - } - } - return allMethods; - } - private static void printSummaryPage(String reportDirectory, Set<String> allPackageNames, Set<String> allClasses, Set<String> testedClasses, Set<String> usedPackageNames) { @@ -688,10 +661,16 @@ System.out.println("Report directory: " + reportDirectory); - printPackageListToFile(reportDirectory, allClasses, testedClasses, usedPackageNames); - printReportForAllClassesInOneFile(reportDirectory, usedPackageNames, testedClasses); - printReportForAllPackages(reportDirectory, usedPackageNames, testedClasses); - printReportForAllClasses(reportDirectory, testedClasses); + Map<String, ClassInfo> classInfoMap = new HashMap<String, ClassInfo>(); + for (String className : allClasses) + { + classInfoMap.put(className, new ClassInfo(reportDirectory, className)); + } + + printPackageListToFile(reportDirectory, allClasses, testedClasses, usedPackageNames, classInfoMap); + printReportForAllClassesInOneFile(reportDirectory, usedPackageNames, testedClasses, classInfoMap); + printReportForAllPackages(reportDirectory, usedPackageNames, testedClasses, classInfoMap); + printReportForAllClasses(reportDirectory, testedClasses, classInfoMap); printSummaryPage(reportDirectory, allPackageNames, allClasses, testedClasses, usedPackageNames); }
--- a/templates/all_packages_template.html Fri Mar 16 11:24:48 2012 +0100 +++ b/templates/all_packages_template.html Fri Mar 23 11:55:40 2012 +0100 @@ -13,7 +13,8 @@ <h1>Package list</h1> <a target='ClassesListFrame' href='all_classes.html'>all classes</a><br /><br /> <table class='package_list'> -<tr><th>package</th><th>classes</th><th>covered</th><th>ratio</th><th>doc</th></tr> +<tr><th>package</th><th colspan='3'>classes</th><th colspan='3'>methods</th><th>doc</th></tr> +<tr><th> </th><th>all</th><th>checked</th><th>ratio</th><th>all</th><th>covered</th><th>ratio</th><th> </th></tr> ${PACKAGE_LIST} </table> </body>
--- a/templates/index.html Fri Mar 16 11:24:48 2012 +0100 +++ b/templates/index.html Fri Mar 23 11:55:40 2012 +0100 @@ -3,7 +3,7 @@ <head> <title>Test coverage report</title> </head> - <frameset cols="25%,75%" title=""> + <frameset cols="30%,70%" title=""> <frameset rows="40%,60%" title=""> <frame src="all_packages.html" name="PackageListFrame" title="Package List" scrolling="yes"> <frame src="all_classes.html" name="ClassesListFrame" title="All public classes" scrolling="yes">
--- a/templates/style.css Fri Mar 16 11:24:48 2012 +0100 +++ b/templates/style.css Fri Mar 23 11:55:40 2012 +0100 @@ -54,7 +54,7 @@ border-width: 1px; padding: 1px; border-style: inset; - border-color: gray; + border-color: black; background-color: #c0c0ff; /* -moz-border-radius: ; */ } @@ -63,7 +63,7 @@ border-width: 1px; padding: 1px; border-style: inset; - border-color: gray; + border-color: black; /* -moz-border-radius: ; */ } @@ -81,7 +81,7 @@ border-width: 1px; padding: 1px; border-style: inset; - border-color: gray; + border-color: black; background-color: #c0c0ff; /* -moz-border-radius: ; */ } @@ -90,7 +90,7 @@ border-width: 1px; padding: 1px; border-style: inset; - border-color: gray; + border-color: black; /* -moz-border-radius: ; */ }