changeset 0:29318fe8d6d0

2012-01-04 Pavel Tisnovsky <ptisnovs@redhat.com> * adding .classpath: * adding .project: * adding .settings/org.eclipse.jdt.core.prefs: * adding AUTHORS: * adding ChangeLog: * adding LICENSE: * adding Makefile: * adding NEWS: * adding README: * adding TODO: * adding class_list.txt: * adding path_to_rt_jar.txt: * adding src/PrintClassList.java: * adding src/PrintPublicMethods.java: * adding src/PrintTestCoverage.java: * adding src/ReportGenerator.java: * adding src/index.html: * adding src/style.css: * adding test_directory.txt: Initial push to this project.
author Pavel Tisnovsky <ptisnovs@redhat.com>
date Wed, 04 Jan 2012 11:20:55 +0100
parents
children 17f81193758a
files .classpath .project .settings/org.eclipse.jdt.core.prefs AUTHORS ChangeLog LICENSE Makefile NEWS README TODO class_list.txt path_to_rt_jar.txt src/PrintClassList.java src/PrintPublicMethods.java src/PrintTestCoverage.java src/ReportGenerator.java src/index.html src/style.css test_directory.txt
diffstat 17 files changed, 2033 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.classpath	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.project	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>MauveTestCoverage</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.settings/org.eclipse.jdt.core.prefs	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,12 @@
+#Tue Dec 20 12:00:42 CET 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AUTHORS	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,10 @@
+The following people have made contibutions to this project.
+Please keep this list in alphabetical order.
+
+Pavel Tisnovsky <ptisnovs@redhat.com>
+
+The following people provided feedback and bug reports:
+
+If your name doesn't appear on either list, but should, if it appears
+on the wrong list, or if your name or mail address is misspelled,
+please let us know.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ChangeLog	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,23 @@
+2012-01-04  Pavel Tisnovsky  <ptisnovs@redhat.com>
+
+	* adding .classpath:
+	* adding .project:
+	* adding .settings/org.eclipse.jdt.core.prefs:
+	* adding AUTHORS:
+	* adding ChangeLog:
+	* adding LICENSE:
+	* adding Makefile:
+	* adding NEWS:
+	* adding README:
+	* adding TODO:
+	* adding class_list.txt:
+	* adding path_to_rt_jar.txt:
+	* adding src/PrintClassList.java:
+	* adding src/PrintPublicMethods.java:
+	* adding src/PrintTestCoverage.java:
+	* adding src/ReportGenerator.java:
+	* adding src/index.html:
+	* adding src/style.css:
+	* adding test_directory.txt:
+	Initial push to this project.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,36 @@
+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 IcedTea; 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.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,138 @@
+# 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.
+
+SOURCEPATH=src
+CLASSDIR=bin
+REPORTDIR=reports
+DOCS=docs
+
+JAVA=java
+JAVAC=javac
+
+# Name of file containing all API classes to be checked by this tool
+CLASS_LIST=class_list.txt
+
+# Name of file where all API classes should be stored
+ALL_CLASS_LIST=all_class_list.txt
+
+# File containing path to directory where (Mauve) test resides
+TEST_DIRECTORY_FILE=test_directory.txt
+TESTDIR=`cat $(TEST_DIRECTORY_FILE)`
+
+# Name of file containing path to rt.jar or other tested Java archive
+PATH_TO_RT_JAR_FILE=path_to_rt_jar.txt
+JARFILE=`cat $(PATH_TO_RT_JAR_FILE)`
+
+
+
+all:	build report
+
+report:	api_class_list public_method_list tested_method_list gen_report
+
+clean:
+	rm -f $(CLASSDIR)/*.class
+	rm -f $(REPORTDIR)/*
+
+build:	$(CLASSDIR)/PrintClassList.class \
+	$(CLASSDIR)/PrintPublicMethods.class \
+	$(CLASSDIR)/PrintTestCoverage.class \
+	$(CLASSDIR)/ReportGenerator.class
+
+api_class_list:	$(REPORTDIR)/$(ALL_CLASS_LIST)
+
+public_method_list:	$(CLASS_LIST)
+	if [ ! -f $(CLASS_LIST) ]; \
+	then \
+	    echo "Please create file $(CLASS_LIST) containing list of classes to check"; \
+	    exit 1; \
+	else \
+	    echo "Ok, file $(CLASS_LIST) exists, go to next step"; \
+	fi
+	while read line; \
+	do \
+	    rm -rf $(REPORTDIR)/$${line}_api.txt; \
+	    java -cp $(CLASSDIR) PrintPublicMethods $${line} > $(REPORTDIR)/$${line}_api.txt; \
+	done < $(CLASS_LIST);
+
+tested_method_list: $(TEST_DIRECTORY_FILE)
+	if [ ! -f $(TEST_DIRECTORY_FILE) ]; \
+	then \
+	    echo "Please create file $(TEST_DIRECTORY_FILE) containing path to test directory"; \
+	    exit 1; \
+	else \
+	    echo "Ok, file $(TEST_DIRECTORY_FILE) exists, go to next step"; \
+	fi
+	if [ ! -d $(TESTDIR) ]; \
+	then \
+	    echo "$(TESTDIR) directory does not exists"; \
+	    exit 1; \
+	else \
+	    echo "Ok, test directory $(TESTDIR) exists"; \
+	fi
+	while read line; \
+	do \
+	    rm -rf $(REPORTDIR)/$${line}_test.txt; \
+	    java -cp $(CLASSDIR) PrintTestCoverage $${line} > $(REPORTDIR)/$${line}_test.txt; \
+	done < $(CLASS_LIST);
+
+$(CLASSDIR)/%.class:	$(SOURCEPATH)/%.java
+	$(JAVAC) -d $(CLASSDIR) -sourcepath $(SOURCEPATH)/ $<
+
+# Target to make the file containing list of all API classes
+$(REPORTDIR)/$(ALL_CLASS_LIST): $(PATH_TO_RT_JAR_FILE)
+	if [ ! -f $(PATH_TO_RT_JAR_FILE) ]; \
+	then \
+	    echo "Please create file $(PATH_TO_RT_JAR_FILE) containing path rt.jar (or other jar)"; \
+	    exit 1; \
+	else \
+	    echo "Ok, file $(PATH_TO_RT_JAR_FILE) exists, go to next step"; \
+	fi
+	if [ ! -f $(JARFILE) ]; \
+	then \
+	    echo "Jar file $(JARFILE) does not exists"; \
+	    exit 1; \
+	else \
+	    echo "Ok, Jar file $(JARFILE) exists"; \
+	fi
+	$(JAVA) -cp $(CLASSDIR) PrintClassList `cat $(PATH_TO_RT_JAR_FILE)` > $(REPORTDIR)/$(ALL_CLASS_LIST)
+
+gen_report:
+	cp -u $(SOURCEPATH)/index.html $(REPORTDIR)
+	cp -u $(SOURCEPATH)/style.css $(REPORTDIR)
+	java -cp $(CLASSDIR) ReportGenerator $(REPORTDIR)/$(ALL_CLASS_LIST) $(CLASS_LIST) $(REPORTDIR)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,52 @@
+Mauve test coverage tool
+========================
+
+This tool could be used to measure test coverage of Java standard API.
+It's based on Mauve tests directory structure, but the tool is able to
+work with other type of tests.
+
+
+
+How it works:
+-------------
+1. First of all, full names of all public class from rt.jar archive are
+   exported to text file (you could use this text file as basis for
+   creating list of selected API classes).
+
+2. In the second step the test tool lists all public methods from selected API
+   classes (this step is based on Reflection API functionality!).
+
+3. In the third step tests bytecode are investigated and all API calls
+   are registered (this means, that all tests should be compiled first).
+
+4. Results from step 2 and step 3 are compared and HTML report is generated.
+
+
+
+Building test coverage tool
+---------------------------
+
+This task is very straighforward, just type:
+make build
+
+
+
+Running test coverage tool
+--------------------------
+
+First you need to configure the tool by editing following three
+text files:
+
+path_to_rt_jar.txt: this file should contains full path to rt.jar
+test_directory.txt: this file should contains path to test directory
+class_list.txt:     list of classes to be tested (you usually don't want
+                    to test whole API)
+
+When these three files are configured, type:
+
+make report
+
+Results are stored in directory "reports", you want to open file "index.html"
+in web browser.
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/class_list.txt	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,2 @@
+java.math.BigDecimal
+java.math.BigInteger
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/path_to_rt_jar.txt	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,2 @@
+/usr/lib/jvm/java/jre/lib/rt.jar
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/PrintClassList.java	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,173 @@
+/*
+  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.io.IOException;
+import java.lang.reflect.Modifier;
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Generate and print list of all public classes which are stored in given JAR
+ * archive. This JAR archive should be accessible through classloader (this
+ * means that -cp should be used in certain situations).
+ * 
+ * This tool could be used against "rt.jar"
+ * 
+ * @author Pavel Tisnovsky
+ */
+public class PrintClassList {
+
+    /**
+     * Generate and print sorted list of public classes.
+     * 
+     * @param pathToJarArchive
+     *            path to rt.jar or other JAR archive to be investigated.
+     */
+    private static void generateClassList(String pathToJarArchive) {
+        try {
+            // open the archive and acquire all its entries
+            JarFile jarFile = new JarFile(pathToJarArchive);
+            Enumeration<JarEntry> entries = jarFile.entries();
+
+            // it's better to print sorted class names
+            // and TreeSet sorted its elements by default
+            Set<String> setOfClassNames = new TreeSet<String>();
+
+            // test each JAR entry
+            while (entries.hasMoreElements()) {
+                JarEntry entry = entries.nextElement();
+                String className = generateClassName(entry.getName());
+                // only public classes are interesting
+                if (isPublicClass(className)) {
+                    setOfClassNames.add(className);
+                }
+            }
+            // now we have the list filled, time to print it
+            for (String className : setOfClassNames) {
+                System.out.println(className);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Returns true if given className represents true class and the class is
+     * public.
+     * 
+     * @param className
+     *            class name
+     * @return true if className represents true class and the class is public
+     */
+    @SuppressWarnings("unchecked")
+    private static boolean isPublicClass(String className) {
+        try {
+            Class clazz = Class.forName(className);
+            // interfaces are not our job 
+            if (clazz.isInterface()) {
+                return false;
+            }
+            int classModifiers = clazz.getModifiers();
+            // we are interested only in public classes
+            if (!Modifier.isPublic(classModifiers)) {
+                return false;
+            }
+        }
+        catch (ClassNotFoundException e) {
+            // it might happen because jar file could
+            // include other files
+            return false;
+        }
+        catch (UnsatisfiedLinkError e) {
+            // it might happen too
+            return false;
+        }
+        catch (ExceptionInInitializerError e) {
+            // it might happen too
+            return false;
+        }
+        catch (NoClassDefFoundError e) {
+            // it might happen too
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Tries to change given JAR entry into proper class name.
+     * 
+     * @param name
+     *            JAR entry name
+     * @return class name transformed from JAR entry name
+     */
+    private static String generateClassName(String name)
+    {
+        String out = name;
+        int postfixIndex = out.indexOf(".class");
+        // remove postfix if its present in name
+        if (postfixIndex > 0)
+        {
+            out = out.substring(0, postfixIndex);
+        }
+        // change path separator into dot separator
+        out = out.replace('/', '.');
+        // I'm not sure about JAR files created on Windows platform
+        out = out.replace(File.separatorChar, '.');
+        return out;
+    }
+
+    /**
+     * Entry point to this tool.
+     * 
+     * @param args
+     *            first argument should contains path to JAR file.
+     */
+    public static void main(String[] args) {
+        String pathToRtJar = "/usr/lib/jvm/java-1.6.0/jre/lib/rt.jar";
+        if (args.length == 1) {
+            pathToRtJar = args[0];
+        }
+        System.err.println("Path to Jar file is set to: " + pathToRtJar);
+        generateClassList(pathToRtJar);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/PrintPublicMethods.java	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,215 @@
+/*
+  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.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * This class generates a list containing all public methods and its argument
+ * types and return type for all classes specified in a file "class_list.txt"
+ * or in a file specified by a command line parameter.
+ * 
+ * @author Pavel Tisnovsky
+ */
+public class PrintPublicMethods
+{
+    /**
+     * Get a Class instance for a given class name or null if something goes
+     * wrong.
+     * 
+     * @param className
+     *            name of a class (including package name)
+     * @return Class instance
+     */
+    @SuppressWarnings("unchecked")
+    private static Class getClass(String className) {
+        Class clazz = null;
+        try {
+            clazz = Class.forName(className);
+            if (!clazz.isInterface() && Modifier.isPublic(clazz.getModifiers())) {
+                return clazz;
+            }
+        }
+        catch (ClassNotFoundException e) {
+            return null;
+        }
+        catch (UnsatisfiedLinkError e) {
+            return null;
+        }
+        catch (ExceptionInInitializerError e) {
+            return null;
+        }
+        catch (NoClassDefFoundError e) {
+            return null;
+        }
+        return null;
+    }
+
+    /**
+     * Remove "public", "static", "final", "synchronized" and "native" prefixes
+     * from full method name;
+     * 
+     * @param methodName
+     *            method name with all prefixes
+     * @return method name without prefixes
+     */
+    private static String acquireMethodName(String methodName) {
+        final String[] prefixes = new String[] {"public", "final", "native", "synchronized", "static"};
+        String methodNameString = methodName;
+        for (String prefix : prefixes) {
+            methodNameString = removePrefix(methodNameString, prefix);
+        }
+        return removeThrowsFromDeclaration(methodNameString);
+    }
+
+    /**
+     * Remove one given prefix from method name.
+     * 
+     * @param methodName
+     *            method name that could contains prefix.
+     * @param prefix
+     *            prefix to be removed.
+     * @return method name without prefixes
+     */
+    private static String removePrefix(String methodName, String prefix) {
+        String prefixStr = prefix + " ";
+        if (methodName.startsWith(prefixStr)) {
+            return methodName.substring(prefixStr.length());
+        }
+        return methodName;
+    }
+
+    /**
+     * Removes throws declaration from method name, i.e.:
+     * 
+     * <pre>
+     * void java.lang.Object.wait() throws java.lang.InterruptedException
+     * </pre>
+     * 
+     * is changed to:
+     * 
+     * <pre>
+     * void java.lang.Object.wait() throws java.lang.InterruptedException
+     * </pre>
+     * 
+     * @param methodName
+     *            method name which could contain throws declaration
+     * @return method name without throws declaration
+     */
+    private static String removeThrowsFromDeclaration(String methodName) {
+        int throwDeclarationIndex = methodName.indexOf(" throws ");
+        if (throwDeclarationIndex > 1) {
+            return methodName.substring(0, throwDeclarationIndex);
+        }
+        return methodName;
+    }
+
+    /**
+     * Print all public method from given class name (if such class exists).
+     * 
+     * @param className
+     *            name of a class (including package name)
+     */
+    @SuppressWarnings("unchecked")
+    private static Set<String> getAllPublicMethodsForClass(String className) {
+        Set<String> out = new TreeSet<String>();
+        Class clazz = getClass(className);
+        if (clazz == null) {
+            return out;
+        }
+        Method[] methods = clazz.getDeclaredMethods();
+        for (Method method : methods) {
+            if (Modifier.isPublic(method.getModifiers())) {
+                String methodName = acquireMethodName(method.toString());
+                out.add(methodName);
+            }
+        }
+        return out;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Set<String> getAllConstructors(String className) {
+        Set<String> out = new TreeSet<String>();
+        Class clazz = getClass(className);
+        if (clazz == null) {
+            return out;
+        }
+        Constructor[] constructors = clazz.getConstructors();
+        for (Constructor constructor : constructors) {
+            if (Modifier.isPublic(constructor.getModifiers())) {
+                String methodName = acquireMethodName(constructor.toString());
+                out.add("<init> " + methodName);
+            }
+        }
+        return out;
+    }
+
+    private static void printAllPublicMethodsAndConstructors(String className)
+    {
+        for (String methodSignature : getAllConstructors(className))
+        {
+            System.out.println(methodSignature);
+        }
+        for (String methodSignature : getAllPublicMethodsForClass(className))
+        {
+            System.out.println(methodSignature);
+        }
+    }
+
+    /**
+     * Entry point to this tool.
+     * 
+     * @param args
+     *            first argument could contains path to file containing class
+     *            list. 
+     */
+    public static void main(String[] args) {
+        if (args.length == 1)
+        {
+            printAllPublicMethodsAndConstructors(args[0].trim());
+        }
+        else
+        {
+            System.err.println("Usage java PrintPublicMethods package.className");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/PrintTestCoverage.java	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,873 @@
+/*
+  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.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+enum ConstantPoolTag
+{
+    CONSTANT_Class(7),
+    CONSTANT_Fieldref(9),
+    CONSTANT_Methodref(10), 
+    CONSTANT_InterfaceMethodref(11),
+    CONSTANT_String(8),
+    CONSTANT_Integer(3),
+    CONSTANT_Float(4),
+    CONSTANT_Long(5),
+    CONSTANT_Double(6),
+    CONSTANT_NameAndType(12),
+    CONSTANT_Utf8(1);
+
+    private int value;
+
+    private ConstantPoolTag(int value)
+    {
+        this.value = value;
+    }
+
+    public int getValue()
+    {
+        return this.value;
+    }
+
+    public static ConstantPoolTag intToConstantPoolTag(int value)
+    {
+        for (ConstantPoolTag val : values())
+        {
+            if (val.value == value)
+            {
+                return val;
+            }
+        }
+        return null;
+    }
+}
+
+abstract class ConstantPoolRecord
+{
+    private ConstantPoolTag tag;
+
+    public ConstantPoolRecord(ConstantPoolTag tag)
+    {
+        this.tag = tag;
+    }
+
+    public ConstantPoolTag getTag()
+    {
+        return this.tag;
+    }
+
+    public void setTag(ConstantPoolTag tag)
+    {
+        this.tag = tag;
+    }
+
+    abstract boolean isRecordOccupyingTwoPoolEntries();
+
+    abstract public String toString(ConstantPoolRecord[] poolEntries);
+}
+
+class ClassRecord extends ConstantPoolRecord
+{
+    private int classNameIndex;
+
+    public ClassRecord(ConstantPoolTag tag, int classNameIndex)
+    {
+        super(tag);
+        this.setClassNameIndex(classNameIndex);
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return false;
+    }
+
+    public void setClassNameIndex(int classNameIndex)
+    {
+        this.classNameIndex = classNameIndex;
+    }
+
+    public int getClassNameIndex()
+    {
+        return this.classNameIndex;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        String className = getClassName(poolEntries);
+        return String.format("%2d   Class           %3d        %s", this.getTag().getValue(), getClassNameIndex(), className);
+    }
+
+    public String getClassName(ConstantPoolRecord[] poolEntries)
+    {
+        Utf8Record string = (Utf8Record)poolEntries[this.getClassNameIndex() - 1];
+        return string.getString();
+    }
+}
+
+class FieldReferenceRecord extends ConstantPoolRecord
+{
+    private int classIndex;
+    private int nameTypeIndex;
+
+    public FieldReferenceRecord(ConstantPoolTag tag, int classIndex, int nameTypeIndex)
+    {
+        super(tag);
+        this.setClassIndex(classIndex);
+        this.setNameTypeIndex(nameTypeIndex);
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return false;
+    }
+
+    public void setNameTypeIndex(int nameTypeIndex)
+    {
+        this.nameTypeIndex = nameTypeIndex;
+    }
+
+    public int getNameTypeIndex()
+    {
+        return this.nameTypeIndex;
+    }
+
+    public void setClassIndex(int classIndex)
+    {
+        this.classIndex = classIndex;
+    }
+
+    public int getClassIndex()
+    {
+        return this.classIndex;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        ClassRecord classRecord = (ClassRecord)poolEntries[this.getClassIndex() - 1];
+        NameAndTypeRecord nameAndTypeRecord = (NameAndTypeRecord)poolEntries[this.getNameTypeIndex() -1];
+        String className = classRecord.getClassName(poolEntries);
+        String name = nameAndTypeRecord.getName(poolEntries);
+        String descriptor = nameAndTypeRecord.getDescriptor(poolEntries);
+
+        return String.format("%2d   FieldRef        %3d %3d    %s.%s:%s", getTag().getValue(), getClassIndex(), getNameTypeIndex(), className, name, descriptor);
+    }
+}
+
+@SuppressWarnings("boxing")
+class MethodReferenceRecord extends ConstantPoolRecord
+{
+    final static Map<Character, String> typeMap = new HashMap<Character, String>();
+    static
+    {
+        typeMap.put('B', "byte");
+        typeMap.put('C', "char");
+        typeMap.put('S', "short");
+        typeMap.put('I', "int");
+        typeMap.put('J', "long");
+        typeMap.put('F', "float");
+        typeMap.put('D', "double");
+        typeMap.put('Z', "boolean");
+    }
+
+    public int classIndex;
+    public int nameTypeIndex;
+
+    public MethodReferenceRecord(ConstantPoolTag tag, int classIndex, int nameTypeIndex)
+    {
+        super(tag);
+        this.classIndex = classIndex;
+        this.nameTypeIndex = nameTypeIndex;
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return false;
+    }
+
+    private int getClassIndex()
+    {
+        return this.classIndex;
+    }
+
+    private int getNameTypeIndex()
+    {
+        return this.nameTypeIndex;
+    }
+
+    public String getPrintableMethodSignature(ConstantPoolRecord[] poolEntries)
+    {
+        NameAndTypeRecord nameAndTypeRecord = (NameAndTypeRecord)poolEntries[this.getNameTypeIndex() -1];
+
+        String className = getClassName(poolEntries);
+        String name = nameAndTypeRecord.getName(poolEntries);
+        String descriptor = nameAndTypeRecord.getDescriptor(poolEntries);
+
+        if (name.equals("<init>")) {
+            return "<init> " + className + formatParameters(descriptor);
+        }
+        return formatReturnType(descriptor) + " " + className + "." + name + formatParameters(descriptor);
+    }
+
+    private String formatParameters(String descriptor)
+    {
+        String params = descriptor.substring(1 + descriptor.indexOf('('), descriptor.indexOf(')'));
+        StringBuffer out = new StringBuffer();
+        int dimensionCount = 0;
+
+        out.append('(');
+        int i = 0;
+        while (i < params.length())
+        {
+            char ch = params.charAt(i);
+            if (typeMap.containsKey(ch))
+            {
+                out.append(typeMap.get(ch));
+                while (dimensionCount > 0)
+                {
+                    dimensionCount--;
+                    out.append("[]");
+                }
+            }
+            if (ch == 'L')
+            {
+                i++;
+                while (params.charAt(i) != ';')
+                {
+                    out.append(params.charAt(i) == '/' ? '.' : params.charAt(i));
+                    i++;
+                }
+            }
+            if (ch == '[')
+            {
+                dimensionCount++;
+            }
+            else
+            {
+                if (i < params.length() - 1)
+                {
+                    out.append(',');
+                }
+            }
+            i++;
+        }
+        out.append(')');
+        return out.toString();
+    }
+
+    private String formatReturnType(String descriptor)
+    {
+        String returnType = descriptor.substring(1 + descriptor.indexOf(')'));
+        StringBuffer out = new StringBuffer();
+        int dimensionCount = 0;
+        int i = 0;
+        while (i < returnType.length())
+        {
+            char ch = returnType.charAt(i);
+            if (typeMap.containsKey(ch))
+            {
+                out.append(typeMap.get(ch));
+                while (dimensionCount > 0)
+                {
+                    dimensionCount--;
+                    out.append("[]");
+                }
+            }
+            if (ch == '[')
+            {
+                dimensionCount++;
+            }
+            if (ch == 'L')
+            {
+                i++;
+                while (returnType.charAt(i) != ';')
+                {
+                    out.append(returnType.charAt(i) == '/' ? '.' : returnType.charAt(i));
+                    i++;
+                }
+            }
+            i++;
+        }
+        return out.toString();
+    }
+
+    public String getClassName(ConstantPoolRecord[] poolEntries)
+    {
+        ClassRecord classRecord = (ClassRecord)poolEntries[this.getClassIndex() - 1];
+        return classRecord.getClassName(poolEntries).replace('/', '.');
+    }
+
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        ClassRecord classRecord = (ClassRecord)poolEntries[this.getClassIndex() - 1];
+        NameAndTypeRecord nameAndTypeRecord = (NameAndTypeRecord)poolEntries[this.getNameTypeIndex() -1];
+        String className = classRecord.getClassName(poolEntries);
+        String name = nameAndTypeRecord.getName(poolEntries);
+        String descriptor = nameAndTypeRecord.getDescriptor(poolEntries);
+
+        return String.format("%2d   MethodRef       %3d %3d    %s.%s:%s", getTag().getValue(), getClassIndex(), getNameTypeIndex(), className, name, descriptor);
+    }
+}
+
+class InterfaceReferenceRecord extends ConstantPoolRecord
+{
+    public int classIndex;
+    public int nameTypeIndex;
+
+    public InterfaceReferenceRecord(ConstantPoolTag tag, int classIndex, int nameTypeIndex)
+    {
+        super(tag);
+        this.classIndex = classIndex;
+        this.nameTypeIndex = nameTypeIndex;
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return false;
+    }
+
+    private int getClassIndex()
+    {
+        return this.classIndex;
+    }
+
+    private int getNameTypeIndex()
+    {
+        return this.nameTypeIndex;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        ClassRecord classRecord = (ClassRecord)poolEntries[this.getClassIndex() - 1];
+        NameAndTypeRecord nameAndTypeRecord = (NameAndTypeRecord)poolEntries[this.getNameTypeIndex() -1];
+        String className = classRecord.getClassName(poolEntries);
+        String name = nameAndTypeRecord.getName(poolEntries);
+        String descriptor = nameAndTypeRecord.getDescriptor(poolEntries);
+
+        return String.format("%2d   InterfaceRef    %3d %3d    %s.%s:%s", getTag().getValue(), getClassIndex(), getNameTypeIndex(), className, name, descriptor);
+    }
+}
+
+class NameAndTypeRecord extends ConstantPoolRecord
+{
+    public int nameIndex;
+    public int descriptorIndex;
+
+    public NameAndTypeRecord(ConstantPoolTag tag, int nameIndex, int descriptorIndex)
+    {
+        super(tag);
+        this.nameIndex = nameIndex;
+        this.descriptorIndex = descriptorIndex;
+    }
+
+    public String getName(ConstantPoolRecord[] poolEntries)
+    {
+        Utf8Record classNameRecord = (Utf8Record)poolEntries[this.nameIndex - 1];
+        return classNameRecord.getString();
+    }
+
+    public String getDescriptor(ConstantPoolRecord[] poolEntries)
+    {
+        Utf8Record descriptorRecord = (Utf8Record)poolEntries[this.descriptorIndex - 1];
+        return descriptorRecord.getString();
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return false;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        String name = getName(poolEntries);
+        String descriptor = getDescriptor(poolEntries);
+        return String.format("%2d   Name and type   %3d %3d    %s  %s", this.getTag().getValue(), this.nameIndex, this.descriptorIndex, name, descriptor);
+    }
+}
+
+class StringRecord extends ConstantPoolRecord
+{
+    public int stringIndex;
+
+    public StringRecord(ConstantPoolTag tag, int stringIndex)
+    {
+        super(tag);
+        this.stringIndex = stringIndex;
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return false;
+    }
+
+    private int getStringIndex()
+    {
+        return this.stringIndex;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        Utf8Record utf8string = (Utf8Record) (poolEntries[this.getStringIndex() - 1]);
+        String string = utf8string.getString();
+        return String.format("%2d   Class           %3d        %s", getTag().getValue(), getStringIndex(), string);
+    }
+}
+
+class IntegerRecord extends ConstantPoolRecord
+{
+    public int integerConstant;
+
+    public IntegerRecord(ConstantPoolTag tag, int integerConstant)
+    {
+        super(tag);
+        this.integerConstant = integerConstant;
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return false;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        return String.format("%2d   %-26s %d", getTag().getValue(), "Integer", this.integerConstant);
+    }
+}
+
+class LongRecord extends ConstantPoolRecord
+{
+    public long longConstant;
+
+    public LongRecord(ConstantPoolTag tag, int high, int low)
+    {
+        super(tag);
+        this.longConstant = (((long) high) << 32) + low;
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return true;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        return String.format("%2d   %-26s %Ld", getTag().getValue(), "Long", this.longConstant);
+    }
+}
+
+class FloatRecord extends ConstantPoolRecord
+{
+    public float floatConstant;
+
+    public FloatRecord(ConstantPoolTag tag, int bits)
+    {
+        super(tag);
+        this.floatConstant = Float.intBitsToFloat(bits);
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return false;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        return String.format("%2d   %-26s %f", getTag().getValue(), "Float", this.floatConstant);
+    }
+}
+
+class DoubleRecord extends ConstantPoolRecord
+{
+    public double doubleConstant;
+
+    public DoubleRecord(ConstantPoolTag tag, int highbits, int lowbits)
+    {
+        super(tag);
+        long val = (((long) highbits) << 32) + lowbits;
+        this.doubleConstant = Double.longBitsToDouble(val);
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return true;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        return String.format("%2d   %-26s %f", getTag().getValue(), "Double", this.doubleConstant);
+    }
+}
+
+class Utf8Record extends ConstantPoolRecord
+{
+    public String string;
+
+    public Utf8Record(ConstantPoolTag tag, String string)
+    {
+        super(tag);
+        this.string= string;
+    }
+
+    public String getString()
+    {
+        return this.string;
+    }
+
+    @Override
+    boolean isRecordOccupyingTwoPoolEntries()
+    {
+        return false;
+    }
+
+    @SuppressWarnings("boxing")
+    @Override
+    public String toString(ConstantPoolRecord[] poolEntries)
+    {
+        return String.format("%2d   String                     \"%s\"", getTag().getValue(), this.getString());
+    }
+}
+
+/**
+ *
+ * @author Pavel Tisnovsky
+ */
+public class PrintTestCoverage
+{
+    /**
+     * Name of file containing directory to tests.
+     */
+    private static final String TEST_DIRECTORY = "test_directory.txt";
+
+    private static int readByte(FileInputStream fin) throws IOException
+    {
+        return fin.read();
+    }
+
+    private static int readTwoBytes(FileInputStream fin) throws IOException
+    {
+        int i1 = readByte(fin);
+        int i2 = readByte(fin);
+        return (i1 << 8) | (i2);
+    }
+
+    private static int readFourBytes(FileInputStream fin) throws IOException
+    {
+        int i1 = readByte(fin);
+        int i2 = readByte(fin);
+        int i3 = readByte(fin);
+        int i4 = readByte(fin);
+        return (i1 << 24) | (i2 << 16) | (i3 << 8) | (i4);
+    }
+
+    @SuppressWarnings("boxing")
+    private static void processMagicNumber(FileInputStream fin) throws Exception
+    {
+        int magic = readFourBytes(fin);
+        System.err.format("Magic constant:     0x%x\n", magic);
+        if (magic != 0xcafebabe)
+        {
+            throw new Exception("Improper magic constant");
+        }
+    }
+
+    @SuppressWarnings("boxing")
+    private static void processClassVersion(FileInputStream fin) throws IOException
+    {
+        int minorVersion = readTwoBytes(fin);
+        int majorVersion = readTwoBytes(fin);
+        System.err.format("Major version:      %d\n", majorVersion);
+        System.err.format("Minor version:      %d\n", minorVersion);
+    }
+
+    private static ConstantPoolRecord readConstantPoolEntry(FileInputStream fin) throws IOException
+    {
+        ConstantPoolTag tag = ConstantPoolTag.intToConstantPoolTag(readByte(fin));
+        switch (tag)
+        {
+            case CONSTANT_Class:
+            {
+                int classNameIndex = readTwoBytes(fin);
+                return new ClassRecord(tag, classNameIndex);
+            }
+            case CONSTANT_Fieldref:
+            {
+                int classIndex = readTwoBytes(fin);
+                int nameTypeIndex = readTwoBytes(fin);
+                return new FieldReferenceRecord(tag, classIndex, nameTypeIndex);
+            }
+            case CONSTANT_InterfaceMethodref:
+            {
+                int classIndex = readTwoBytes(fin);
+                int nameTypeIndex = readTwoBytes(fin);
+                return new InterfaceReferenceRecord(tag, classIndex, nameTypeIndex);
+            }
+            case CONSTANT_Methodref:
+            {
+                int classIndex = readTwoBytes(fin);
+                int nameTypeIndex = readTwoBytes(fin);
+                return new MethodReferenceRecord(tag, classIndex, nameTypeIndex);
+            }
+            case CONSTANT_NameAndType:
+            {
+                int nameIndex = readTwoBytes(fin);
+                int descriptorIndex = readTwoBytes(fin);
+                return new NameAndTypeRecord(tag, nameIndex, descriptorIndex);
+            }
+            case CONSTANT_String:
+            {
+                int stringIndex = readTwoBytes(fin);
+                return new StringRecord(tag, stringIndex);
+            }
+            case CONSTANT_Integer:
+            {
+                int constant = readFourBytes(fin);
+                return new IntegerRecord(tag, constant);
+            }
+            case CONSTANT_Long:
+            {
+                int high = readFourBytes(fin);
+                int low = readFourBytes(fin);
+                return new LongRecord(tag, high, low);
+            }
+            case CONSTANT_Float:
+            {
+                int bits = readFourBytes(fin);
+                return new FloatRecord(tag, bits);
+            }
+            case CONSTANT_Double:
+            {
+                int highbits = readFourBytes(fin);
+                int lowbits = readFourBytes(fin);
+                return new DoubleRecord(tag, highbits, lowbits);
+            }
+            case CONSTANT_Utf8:
+            {
+                int length = readTwoBytes(fin);
+                StringBuffer buf = new StringBuffer(length);
+                for (int i = 0; i < length; i++)
+                {
+                    buf.append((char)readByte(fin));
+                }
+                return new Utf8Record(tag, buf.toString());
+            }
+            default:
+                System.out.println("Unknown tag " + tag);
+                return null;
+        }
+    }
+
+    @SuppressWarnings("boxing")
+    private static ConstantPoolRecord[] processContantPool(FileInputStream fin) throws IOException
+    {
+        ConstantPoolRecord[] poolEntries = null;
+
+        int constantPoolCount = readTwoBytes(fin) - 1;
+
+        System.err.format("\nConstant pool size: %d\n", constantPoolCount);
+        poolEntries = new ConstantPoolRecord[constantPoolCount];
+
+        int i = 0;
+        while (i < constantPoolCount)
+        {
+            ConstantPoolRecord record = readConstantPoolEntry(fin);
+            poolEntries[i] = record;
+            i += record.isRecordOccupyingTwoPoolEntries() ? 2 : 1;
+            //System.err.println(i + "\t" + record.getTag());
+        }
+
+        return poolEntries;
+    }
+
+    @SuppressWarnings("unused")
+    private static void printConstantPool(ConstantPoolRecord[] poolEntries)
+    {
+        for (ConstantPoolRecord record : poolEntries)
+        {
+            if (record != null && !(record instanceof Utf8Record))
+            {
+                System.out.println(record.toString(poolEntries));
+            }
+        }
+    }
+
+    private static void printMethodList(String testedClassName, ConstantPoolRecord[] poolEntries, Set<String> methodSet)
+    {
+        for (ConstantPoolRecord record : poolEntries)
+        {
+            if (record != null && (record instanceof MethodReferenceRecord))
+            {
+                MethodReferenceRecord rec = (MethodReferenceRecord) record;
+                if (testedClassName.equals(rec.getClassName(poolEntries)))
+                {
+                    methodSet.add(rec.getPrintableMethodSignature(poolEntries));
+                }
+            }
+        }
+    }
+
+    private static void printTestCoverageForOneTestClass(String testedClassName, File directory, String fileName, Set<String> methodSet)
+    {
+        FileInputStream fin = null;
+        try
+        {
+            fin = new FileInputStream(new File(directory, fileName));
+            try
+            {
+                processMagicNumber(fin);
+                processClassVersion(fin);
+                ConstantPoolRecord[] poolEntries = processContantPool(fin);
+                //printConstantPool(poolEntries);
+                printMethodList(testedClassName, poolEntries, methodSet);
+            }
+            catch (Exception e)
+            {
+                e.printStackTrace();
+            }
+            finally
+            {
+                try
+                {
+                    fin.close();
+                }
+                catch (IOException e)
+                {
+                    e.printStackTrace();
+                }
+            }
+        }
+        catch (FileNotFoundException e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    private static void printTestCoverage(String pathToTests, String testedClassName)
+    {
+        Set<String> methodSet = new TreeSet<String>();
+        String className = testedClassName.replace('.', '/');
+        File list = new File(pathToTests, className);
+        if (!list.isDirectory())
+        {
+            throw new RuntimeException(list.getAbsolutePath() + " is not a proper directory name");
+        }
+        for (String fileName : list.list())
+        {
+            if (fileName.endsWith(".class"))
+            {
+                System.err.println("Checked file: " + fileName);
+                printTestCoverageForOneTestClass(testedClassName, list, fileName, methodSet);
+            }
+        }
+        for (String method : methodSet)
+        {
+            System.out.println(method);
+        }
+    }
+
+    private static String readPathToTest() throws IOException
+    {
+        BufferedReader fin = new BufferedReader(new FileReader(TEST_DIRECTORY));
+        String directory = fin.readLine();
+        return directory;
+    }
+
+    private static void doPrintTestCoverage(String className)
+    {
+        String pathToTests = null;
+        try
+        {
+            pathToTests = readPathToTest();
+            printTestCoverage(pathToTests, className);
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    public static void main(String[] args)
+    {
+        if (args.length == 1)
+        {
+            String className = args[0].trim();
+            doPrintTestCoverage(className);
+        }
+        else
+        {
+            System.err.println("Usage java PrintTestCoverage package.className");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ReportGenerator.java	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,426 @@
+/*
+  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.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Set;
+import java.util.TreeSet;
+
+
+
+/**
+ * Report generator which process .txt files generated by PrintPublicMethods and
+ * PrintTestCoverage classes.
+ * 
+ * @author Pavel Tisnovsky
+ */
+public class ReportGenerator
+{
+    private static Set<String> readAllClasses(String allClassListFileName)
+    {
+        BufferedReader reader = null;
+        Set<String> allClasses = new TreeSet<String>();
+        try
+        {
+            reader = new BufferedReader(new FileReader(allClassListFileName));
+            String line;
+            while ((line = reader.readLine()) != null)
+            {
+                allClasses.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 allClasses;
+    }
+
+    private static Set<String> preparePackageNames(Set<String> allClasses)
+    {
+        Set<String> packages = new TreeSet<String>();
+        for (String className : allClasses)
+        {
+            String packageName = className.substring(0, className.lastIndexOf('.'));
+            if (!packageName.startsWith("com.") && !packageName.startsWith("sun"))
+            {
+                packages.add(packageName);
+            }
+        }
+        return packages;
+    }
+
+    private static void printPackageListToFile(String reportDirectory, Set<String> allClasses, Set<String> packageNames)
+    {
+        BufferedWriter fout = null;
+        try
+        {
+            fout = new BufferedWriter(new FileWriter(new File(reportDirectory, "all_packages.html")));
+            fout.write("<html>\n");
+            fout.write("<body>\n");
+            fout.write("<h1>Package list</h1>\n");
+            fout.write("<a target='ClassesListFrame' href='all_classes.html'>all classes</a><br /><br />\n");
+            for (String packageName : packageNames)
+            {
+                fout.write("<a target='ClassesListFrame' href='" + packageName + ".html'>" + packageName + "</a><br />\n");
+            }
+            fout.write("</body>\n");
+            fout.write("</html>\n");
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+        finally
+        {
+            try
+            {
+                if (fout != null)
+                {
+                    fout.close();
+                }
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static void createFileForPackage(String reportDirectory, String packageName, Set<String> testedClasses)
+    {
+        BufferedWriter fout = null;
+        try
+        {
+            fout = new BufferedWriter(new FileWriter(new File(reportDirectory, packageName + ".html")));
+            fout.write("<html>\n");
+            fout.write("<body>\n");
+            fout.write("<h1>Class list</h1>\n");
+            for (String className : testedClasses)
+            {
+                if (className.startsWith(packageName))
+                {
+                    fout.write("<a target='ResultsFrame' href='" + className + ".html'>" + className + "</a><br>\n");
+                }
+            }
+            fout.write("</body>\n");
+            fout.write("</html>\n");
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+        finally
+        {
+            try
+            {
+                if (fout != null)
+                {
+                    fout.close();
+                }
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static void createFileForClass(String reportDirectory, String testClass, Set<String> allMethods, Set<String> apiMethods, Set<String> testedMethods)
+    {
+        BufferedWriter fout = null;
+        try
+        {
+            fout = new BufferedWriter(new FileWriter(new File(reportDirectory, testClass + ".html")));
+            fout.write("<html>\n");
+            fout.write("<head>\n");
+            fout.write("<title>" + testClass + "</title>\n");
+            fout.write("</head>\n");
+            fout.write("<body>\n");
+            fout.write("<h1>Class " + testClass + "</h1>\n");
+            fout.write("<table>\n");
+            fout.write("<tr><th>Method</th><th><a href='"+testClass+"_api.txt'>API</a></th><th><a href='"+testClass+"_test.txt'>Tested</a></th></tr>\n");
+            for (String methodName : allMethods)
+            {
+                fout.write("<tr><td>" + constructPrintedMethodName(methodName) + "</td>");
+                fout.write(printMethodCoverage(methodName, apiMethods));
+                fout.write(printMethodCoverage(methodName, testedMethods));
+                fout.write("</tr>\n");
+            }
+            fout.write("</table>\n");
+            fout.write("</body>\n");
+            fout.write("</html>\n");
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+        finally
+        {
+            try
+            {
+                if (fout != null)
+                {
+                    fout.close();
+                }
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static String constructPrintedMethodName(String methodName)
+    {
+        String printedMethodName = methodName.replace("<", "&lt;").replace(">", "&gt;");
+        int returnTypeEnds = printedMethodName.indexOf(' ');
+        int parametersBegin = printedMethodName.indexOf('(');
+        String returnType = printedMethodName.substring(0, printedMethodName.indexOf(' '));
+        String name = printedMethodName.substring(returnTypeEnds, parametersBegin);
+        String params = printedMethodName.substring(parametersBegin);
+
+        return String.format(
+            "<span style='color:#000080'>%s</span>" +
+            "<span style='color:#008000'>%s</span>" +
+            "<span style='color:#804000'>%s</span>", returnType, name, params);
+    }
+
+    private static String printMethodCoverage(String methodName, Set<String> methodSet)
+    {
+        if (methodSet.contains(methodName))
+        {
+            return "<td style='background:#80ff80'>present</td>";
+        }
+        return "<td style='background:#ff8080'>absent</td>";
+    }
+
+    private static Set<String> prepareUsedPackageNames(Set<String> allPackageNames, Set<String> testedClasses)
+    {
+        Set<String> out = new TreeSet<String>();
+        for (String packageName : allPackageNames)
+        {
+            for (String testClass : testedClasses)
+            {
+                if (testClass.startsWith(packageName))
+                {
+                    out.add(packageName);
+                    break;
+                }
+            }
+        }
+        return out;
+    }
+
+    private static void printReportForAllPackages(String reportDirectory, Set<String> usedPackageNames,
+                    Set<String> testedClasses)
+    {
+        for (String packageName : usedPackageNames)
+        {
+            createFileForPackage(reportDirectory, packageName, testedClasses);
+        }
+    }
+
+    private static void printReportForAllClasses(String reportDirectory, Set<String> testedClasses)
+    {
+        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);
+            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 FileReader(fileName));
+            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 printReportForAllClassesInOneFile(String reportDirectory, Set<String> usedPackageNames,
+                    Set<String> testedClasses)
+    {
+        BufferedWriter fout = null;
+        try
+        {
+            fout = new BufferedWriter(new FileWriter(new File(reportDirectory, "all_classes.html")));
+            fout.write("<html>\n");
+            fout.write("<body>\n");
+            fout.write("<h1>Classes list</h1>");
+            for (String packageName : usedPackageNames)
+            {
+                fout.write("<h2>Package " + packageName + "</h2>\n");
+                for (String className : testedClasses)
+                {
+                    if (className.startsWith(packageName))
+                    {
+                        fout.write("<a target='ResultsFrame' href='" + className + ".html'>" + className + "</a><br>\n");
+                    }
+                }
+            }
+            fout.write("</body>\n");
+            fout.write("</html>\n");
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+        finally
+        {
+            try
+            {
+                if (fout != null)
+                {
+                    fout.close();
+                }
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static void prepareReport(String allClassListFileName, String testedClassListFileName,
+                    String reportDirectory)
+    {
+        Set<String> allClasses = readAllClasses(allClassListFileName);
+        Set<String> testedClasses = readAllClasses(testedClassListFileName);
+        Set<String> allPackageNames = preparePackageNames(allClasses);
+        Set<String> usedPackageNames = prepareUsedPackageNames(allPackageNames, testedClasses);
+
+        System.out.println("All class list:    " + allClassListFileName);
+        System.out.println("Read " + allClasses.size() + " class names");
+
+        System.out.println("Tested class list: " + testedClassListFileName);
+        System.out.println("Read " + testedClasses.size() + " class names");
+
+        System.out.println("Setting list of " + allPackageNames.size() + " all package names");
+        System.out.println("Setting list of " + usedPackageNames.size() + " used package names");
+
+        System.out.println("Report directory:  " + reportDirectory);
+
+        printPackageListToFile(reportDirectory, allClasses, usedPackageNames);
+        printReportForAllClassesInOneFile(reportDirectory, usedPackageNames, testedClasses);
+        printReportForAllPackages(reportDirectory, usedPackageNames, testedClasses);
+        printReportForAllClasses(reportDirectory, testedClasses);
+    }
+
+    public static void main(String[] args)
+    {
+        if (args.length != 3)
+        {
+            System.err.println("Usage allClassListFileName classListFileName reportDirectory");
+            System.exit(1);
+        }
+        String allClassListFileName = args[0];
+        String testedClassListFileName = args[1];
+        String reportDirectory = args[2];
+        prepareReport(allClassListFileName, testedClassListFileName, reportDirectory);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/index.html	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
+<html>
+    <head>
+        <title>Test coverage report</title>
+    </head>
+        <frameset cols="20%,80%" 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">
+        </frameset>
+        <frame src="all_results.html" name="ResultsFrame" title="Test coverage" scrolling="yes">
+        <noframes>
+            <h2>Frame Alert</h2>
+                <p>This document is designed to be viewed using the frames
+                feature. If you see this message, you are using a
+                non-frame-capable web client.</p>
+        </noframes>
+    </frameset>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/style.css	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,27 @@
+body      {font-family: arial, helvetica, sans-serif; color:#000000; text-align:justify; background-color:#ffffff; margin-left: 0px; margin-top: 0px}
+h1        {font-family: arial, helvetica, sans-serif; color:#000000; background:#80a0a0; text-align:center; padding-left: 1em; margin: 0}
+h2        {font-family: arial, helvetica, sans-serif; color:#000000; background:#80a0a0; padding-left: 1em; padding-right:1cm}
+h3        {font-family: arial, helvetica, sans-serif; color:#000000; background:#a0a080; padding-left: 1em; padding-right:1cm}
+h4        {font-family: arial, helvetica, sans-serif; color:#000000; background:#c0c0a0; padding-left: 1em; padding-right:1cm; margin-bottom: 5px}
+a         {font-family: arial, helvetica, sans-serif; color:#0000ff; text-decoration:none}
+a:link    {color:#0000ff}
+a:visited {color:#0000ff}
+a:visited {color:#0000ff}
+a:hover   {color:#ffffff; background:#404040}
+p         {font-family: arial, helvetica, sans-serif; color:#000000; text-align:justify; padding-left:1em; padding-right:1em}
+li        {font-family: arial, helvetica, sans-serif; color:#000000; text-align:justify}
+pre       {}
+tr        {font-family: arial, helvetica, sans-serif; text-align:left}
+td        {font-family: arial, helvetica, sans-serif; text-align:left}
+td.center {font-family: arial, helvetica, sans-serif; text-align:center}
+th.center {font-family: arial, helvetica, sans-serif; text-align:center}
+
+.forms    {background-color: #f0f0dd; vertical-align: top; width: 720px; border-collapse: collapse; border-color:#808080; margin-left:32px}
+
+.present-method     {background-color:#006000}
+.absent-method      {background-color:#600000}
+
+.method-return-type {}
+.method-name        {}
+.method-params      {}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test_directory.txt	Wed Jan 04 11:20:55 2012 +0100
@@ -0,0 +1,1 @@
+/home/ptisnovs/temp/testlet/