changeset 235:114a981d3552

added posibility for junit to export reports to xml, addes set of styles for easy navigation inside tests-output file (transformed to html)
author Jiri Vanek <jvanek@redhat.com>
date Tue, 10 May 2011 11:58:19 +0200
parents f93285fdccdf
children 2b1a69f4c54b
files ChangeLog Makefile.am tests/junit-runner/CommandLine.java tests/junit-runner/JunitLikeXmlOutputListener.java tests/report-styles/index.html.in tests/report-styles/index.js tests/report-styles/jreport.xsl tests/report-styles/report.css
diffstat 8 files changed, 605 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon May 09 21:58:48 2011 +0200
+++ b/ChangeLog	Tue May 10 11:58:19 2011 +0200
@@ -1,3 +1,22 @@
+2011-05-10 Jiri Vanek <jvanek@redhat.com>
+
+	* tests/junit-runner/JunitLikeXmlOutputListener: This listener exports
+	results of junit in xml which "follows junit-output schema". Extended
+	for date, duration and some statististics for future purpose
+	*tests/report-sytles/index.html.in : file which provides runtime
+	transformation	of tests-output.xml and report.xml
+	* tests/report-styles/index.js: runtime transformation script and fast
+	navigation functions
+	* tests/report-styles/report.css: styles for transformed result
+	* tests/report-styles/jreport.xsl: template for human-readable
+	xml->html transformation. 
+	* Makefile.am (javaws, itweb_settings): New variables for report-styles 
+	directory; (edit_tests_index) - sed makro for replacing variables
+	inside 	index.html.in; (index.html) - goal for generating index.html
+	file from index.html.in and copying styles fiels; (run-netx-unit-tests) 
+	cloned stdout/err (clean-netx-unit-tests) cleaning styles dir and 
+	index.html
+
 2011-05-09  Jiri Vanek  <jvanek@redhat.com>
 	* tests/junit-runner/CommandLine.java:r added skipping of inner 
 	classes and one jnlp file from sources package.
--- a/Makefile.am	Mon May 09 21:58:48 2011 +0200
+++ b/Makefile.am	Tue May 10 11:58:19 2011 +0200
@@ -6,14 +6,18 @@
 NETX_EXTRA_DIR=$(abs_top_srcdir)/extra/net/sourceforge/javaws/about/resources
 NETX_EXTRA_DIST_DIR=$(abs_top_builddir)/extra-lib/net/sourceforge/javaws/about/resources
 
+REPORT_STYLES_DIRNAME=report-styles
+
 TESTS_SRCDIR=$(abs_top_srcdir)/tests
-TESTS_DIR=$(abs_top_builddir)/tests.build
-
 NETX_UNIT_TEST_SRCDIR=$(TESTS_SRCDIR)/netx/unit
-NETX_UNIT_TEST_DIR=$(TESTS_DIR)/netx/unit
+TESTS_STYLES_SRCDIR=$(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)
+JUNIT_RUNNER_SRCDIR=$(TESTS_SRCDIR)/junit-runner
 
+TESTS_DIR=$(abs_top_builddir)/tests.build
+NETX_UNIT_TEST_DIR=$(TESTS_DIR)/netx/unit
+TESTS_STYLES_DIR=$(TESTS_DIR)/$(REPORT_STYLES_DIRNAME)
 JUNIT_RUNNER_DIR=$(TESTS_DIR)/junit-runner
-JUNIT_RUNNER_SRCDIR=$(TESTS_SRCDIR)/junit-runner
+
 
 JUNIT_RUNNER_JAR=$(abs_top_builddir)/junit-runner.jar
 
@@ -122,6 +126,14 @@
   -e 's|[@]JAVA[@]|$(JAVA)|g' \
   -e 's|[@]JRE[@]|$(JRE)|g'
 
+edit_tests_index = sed \
+  -e 's|[@]data_path_unit[@]|netx/unit/tests-output.xml|g' \
+  -e 's|[@]data_path_dist[@]|netx/dist/tests-output.xml|g' \
+  -e 's|[@]css_styles[@]|$(REPORT_STYLES_DIRNAME)/report.css|g' \
+  -e 's|[@]xslt_script[@]|$(REPORT_STYLES_DIRNAME)/index.js|g' \
+  -e 's|[@]sheet_path_unit[@]|$(REPORT_STYLES_DIRNAME)/jreport.xsl|g' \
+  -e 's|[@]sheet_path_dist[@]|$(REPORT_STYLES_DIRNAME)/jreport.xsl|g'
+
 # Top-Level Targets
 # =================
 
@@ -450,6 +462,13 @@
 netx-unit-tests-source-files.txt:
 	find $(NETX_UNIT_TEST_SRCDIR) -name '*.java' | sort > $@
 
+$(TESTS_DIR)/index.html: stamps/netx-unit-tests-compile.stamp
+	mkdir $(TESTS_STYLES_DIR)/
+	cp $(TESTS_STYLES_SRCDIR)/*.css $(TESTS_STYLES_DIR)/
+	cp $(TESTS_STYLES_SRCDIR)/*.xsl $(TESTS_STYLES_DIR)/
+	cp $(TESTS_STYLES_SRCDIR)/*.js $(TESTS_STYLES_DIR)/
+	$(edit_tests_index) < $(TESTS_STYLES_SRCDIR)/index.html.in > $@
+
 stamps/netx-unit-tests-compile.stamp: stamps/netx.stamp \
  netx-unit-tests-source-files.txt
 	mkdir -p $(NETX_UNIT_TEST_DIR) && \
@@ -460,7 +479,7 @@
 	mkdir -p stamps && \
 	touch $@
 
-run-netx-unit-tests: stamps/netx-unit-tests-compile.stamp \
+run-netx-unit-tests: stamps/netx-unit-tests-compile.stamp $(TESTS_DIR)/index.html \
  $(JUNIT_RUNNER_JAR)
 	cp {$(NETX_UNIT_TEST_SRCDIR),$(NETX_UNIT_TEST_DIR)}/net/sourceforge/jnlp/basic.jnlp
 	cd $(NETX_UNIT_TEST_DIR) ; \
@@ -472,7 +491,10 @@
 	done ; \
 	echo $$class_names ; \
 	CLASSPATH=$(NETX_DIR)/lib/classes.jar:$(JUNIT_JAR):$(JUNIT_RUNNER_JAR):. \
-	  $(BOOT_DIR)/bin/java -Xbootclasspath:$(RUNTIME) CommandLine $$class_names
+	  $(BOOT_DIR)/bin/java -Xbootclasspath:$(RUNTIME) CommandLine $$class_names \
+	  > stdout.log 2> stderr.log ; \
+	cat stdout.log ; \
+	cat stderr.log >&2
 
 clean-netx-tests: clean-netx-unit-tests clean-junit-runner
 	if [ -e $(TESTS_DIR)/netx ]; then \
@@ -485,6 +507,8 @@
 	rm -f $(JUNIT_RUNNER_JAR)
 
 clean-netx-unit-tests:
+	rm -rf $(TESTS_STYLES_DIR)
+	rm -f $(TESTS_DIR)/index.html
 	rm -f netx-unit-tests-source-files.txt
 	rm -rf $(NETX_UNIT_TEST_DIR)
 	rm -f stamps/netx-unit-tests-compile.stamp
--- a/tests/junit-runner/CommandLine.java	Mon May 09 21:58:48 2011 +0200
+++ b/tests/junit-runner/CommandLine.java	Tue May 10 11:58:19 2011 +0200
@@ -7,6 +7,7 @@
  * http://www.eclipse.org/legal/cpl-v10.html
  */
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -41,6 +42,8 @@
                 system.out().println("ERROR: Could not find class: " + each);
             }
         }
+        RunListener jXmlOutput = new JunitLikeXmlOutputListener(system, new File("tests-output.xml"));
+        addListener(jXmlOutput);
         RunListener listener = new LessVerboseTextListener(system);
         addListener(listener);
         Result result = run(classes.toArray(new Class[0]));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/junit-runner/JunitLikeXmlOutputListener.java	Tue May 10 11:58:19 2011 +0200
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * This file is made available under the terms of the Common Public License
+ * v1.0 which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+
+import java.io.BufferedWriter;
+import java.io.File;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+
+import org.junit.internal.JUnitSystem;
+import org.junit.runner.Description;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+/**
+ * This class listens for events in junit testsuite and wrote output to xml.
+ * Xml tryes to follow ant-tests schema, and is enriched for by-class statistics
+ * stdout and err elements are added, but must be filled from elsewhere (eg tee
+ * in make) as junit suite and listener run from our executer have no access to
+ * them.
+ * 
+ */
+public class JunitLikeXmlOutputListener extends RunListener {
+
+    private BufferedWriter writer;
+    private Failure testFailed = null;
+    private static final String ROOT = "testsuite";
+    private static final String DATE_ELEMENT = "date";
+    private static final String TEST_ELEMENT = "testcase";
+    private static final String TEST_NAME_ATTRIBUTE = "name";
+    private static final String TEST_TIME_ATTRIBUTE = "time";
+    private static final String TEST_ERROR_ELEMENT = "error";
+    private static final String TEST_CLASS_ATTRIBUTE = "classname";
+    private static final String ERROR_MESSAGE_ATTRIBUTE = "message";
+    private static final String ERROR_TYPE_ATTRIBUTE = "type";
+    private static final String SOUT_ELEMENT = "system-out";
+    private static final String SERR_ELEMENT = "system-err";
+    private static final String CDATA_START = "<![CDATA[";
+    private static final String CDATA_END = "]]>";
+    private static final String TEST_CLASS_ELEMENT = "class";
+    private static final String STATS_ELEMENT = "stats";
+    private static final String CLASSES_ELEMENT = "classes";
+    private static final String SUMMARY_ELEMENT = "summary";
+    private static final String SUMMARY_TOTAL_ELEMENT = "total";
+    private static final String SUMMARY_PASSED_ELEMENT = "passed";
+    private static final String SUMMARY_FAILED_ELEMENT = "failed";
+    private static final String SUMMARY_IGNORED_ELEMENT = "ignored";
+    private long testStart;
+
+    private class ClassCounter {
+
+        int total;
+        int failed;
+        int passed;
+        long time = 0;
+    }
+    Map<String, ClassCounter> classStats = new HashMap<String, ClassCounter>();
+
+    public JunitLikeXmlOutputListener(JUnitSystem system, File f) {
+        try {
+            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "UTF-8"));
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    @Override
+    public void testRunStarted(Description description) throws Exception {
+        openElement(ROOT);
+        writeElement(DATE_ELEMENT, new Date().toString());
+    }
+
+    private void openElement(String name) throws IOException {
+        openElement(name, null);
+    }
+
+    private void openElement(String name, Map<String, String> atts) throws IOException {
+        StringBuilder attString = new StringBuilder();
+        if (atts != null) {
+            attString.append(" ");
+            Set<Entry<String, String>> entries = atts.entrySet();
+            for (Entry<String, String> entry : entries) {
+                attString.append(entry.getKey()).append("=\"").append(attributize(entry.getValue())).append("\"");
+                attString.append(" ");
+            }
+        }
+        writer.write("<" + name + attString.toString() + ">");
+        writer.newLine();
+    }
+
+    private static String attributize(String s) {
+        return s.replace("&", "&amp;").replace("<", "&lt;");
+    }
+
+    private void closeElement(String name) throws IOException {
+        writer.newLine();
+        writer.write("</" + name + ">");
+        writer.newLine();
+    }
+
+    private void writeContent(String content) throws IOException {
+        writer.write(CDATA_START + content + CDATA_END);
+    }
+
+    private void writeElement(String name, String content) throws IOException {
+        writeElement(name, content, null);
+    }
+
+    private void writeElement(String name, String content, Map<String, String> atts) throws IOException {
+        openElement(name, atts);
+        writeContent(content);
+        closeElement(name);
+    }
+
+    @Override
+    public void testStarted(Description description) throws Exception {
+        testFailed = null;
+        testStart = System.nanoTime()/1000l/1000l;
+    }
+
+    @Override
+    public void testFailure(Failure failure) throws IOException {
+        testFailed = failure;
+    }
+
+    @Override
+    public void testFinished(org.junit.runner.Description description) throws Exception {
+        long testTime = System.nanoTime()/1000l/1000l - testStart;
+        double testTimeSeconds = ((double) testTime) / 1000d;
+
+        Map<String, String> testcaseAtts = new HashMap<String, String>(3);
+        NumberFormat formatter = new DecimalFormat("#0.0000");
+        String stringedTime = formatter.format(testTimeSeconds);
+        stringedTime.replace(",", ".");
+        testcaseAtts.put(TEST_TIME_ATTRIBUTE, stringedTime);
+        testcaseAtts.put(TEST_CLASS_ATTRIBUTE, description.getClassName());
+        testcaseAtts.put(TEST_NAME_ATTRIBUTE, description.getMethodName());
+
+        openElement(TEST_ELEMENT, testcaseAtts);
+        if (testFailed != null) {
+            Map<String, String> errorAtts = new HashMap<String, String>(3);
+
+            errorAtts.put(ERROR_MESSAGE_ATTRIBUTE, testFailed.getMessage());
+            int i = testFailed.getTrace().indexOf(":");
+            if (i >= 0) {
+                errorAtts.put(ERROR_TYPE_ATTRIBUTE, testFailed.getTrace().substring(0, i));
+            } else {
+                errorAtts.put(ERROR_TYPE_ATTRIBUTE, "?");
+            }
+
+            writeElement(TEST_ERROR_ELEMENT, testFailed.getTrace(), errorAtts);
+        }
+
+        closeElement(TEST_ELEMENT);
+        writer.flush();
+
+        ClassCounter cc = classStats.get(description.getClassName());
+        if (cc == null) {
+            cc = new ClassCounter();
+            classStats.put(description.getClassName(), cc);
+        }
+        cc.total++;
+        cc.time += testTime;
+        if (testFailed == null) {
+            cc.passed++;
+        } else {
+
+            cc.failed++;
+        }
+    }
+
+    @Override
+    public void testRunFinished(Result result) throws Exception {
+
+        writeElement(SOUT_ELEMENT, "@sout@");
+        writeElement(SERR_ELEMENT, "@serr@");
+        openElement(STATS_ELEMENT);
+        openElement(SUMMARY_ELEMENT);
+        int passed = result.getRunCount() - result.getFailureCount() - result.getIgnoreCount();
+        int failed = result.getFailureCount();
+        int ignored = result.getIgnoreCount();
+        writeElement(SUMMARY_TOTAL_ELEMENT, String.valueOf(result.getRunCount()));
+        writeElement(SUMMARY_FAILED_ELEMENT, String.valueOf(failed));
+        writeElement(SUMMARY_IGNORED_ELEMENT, String.valueOf(ignored));
+        writeElement(SUMMARY_PASSED_ELEMENT, String.valueOf(passed));
+        closeElement(SUMMARY_ELEMENT);
+        openElement(CLASSES_ELEMENT);
+        Set<Entry<String, ClassCounter>> e = classStats.entrySet();
+        for (Entry<String, ClassCounter> entry : e) {
+
+            Map<String, String> testcaseAtts = new HashMap<String, String>(3);
+            testcaseAtts.put(TEST_NAME_ATTRIBUTE, entry.getKey());
+            testcaseAtts.put(TEST_TIME_ATTRIBUTE, String.valueOf(entry.getValue().time));
+
+            openElement(TEST_CLASS_ELEMENT, testcaseAtts);
+            writeElement(SUMMARY_PASSED_ELEMENT, String.valueOf(entry.getValue().passed));
+            writeElement(SUMMARY_FAILED_ELEMENT, String.valueOf(entry.getValue().failed));
+            writeElement(SUMMARY_IGNORED_ELEMENT, String.valueOf(entry.getValue().total - entry.getValue().failed - entry.getValue().passed));
+            writeElement(SUMMARY_TOTAL_ELEMENT, String.valueOf(entry.getValue().total));
+
+            closeElement(TEST_CLASS_ELEMENT);
+        }
+        closeElement(CLASSES_ELEMENT);
+        closeElement(STATS_ELEMENT);
+
+        closeElement(ROOT);
+        writer.flush();
+        writer.close();
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/report-styles/index.html.in	Tue May 10 11:58:19 2011 +0200
@@ -0,0 +1,25 @@
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+    <script src="@xslt_script@">
+    </script>
+    <link href="@css_styles@" rel="stylesheet" type="text/css"/>
+  </head>
+  <body onload="xslt('@sheet_path_unit@','@data_path_unit@','wholePage2');
+		xslt('@sheet_path_dist@','@data_path_dist@','wholePage4');
+		">
+
+<div>
+<hr/>
+<a name="JunitTests">Unit-tests:</a> [<a href="#JdistTests">dist tests</a>]
+<hr/>
+    <div id="wholePage2"/>
+</div>
+
+<hr/>
+<a name="JdistTests">Dist-tests:</a> [<a href="#JunitTests">unit tests</a>]
+<hr/>
+    <div id="wholePage4"/>
+</div>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/report-styles/index.js	Tue May 10 11:58:19 2011 +0200
@@ -0,0 +1,67 @@
+
+if(typeof String.prototype.trim !== 'function') {   String.prototype.trim = function() {     return this.replace(/^\s+|\s+$/g, '');    } }
+
+
+function negateIdDisplay(which){
+	var e = document.getElementById(which);
+ 		if (e.style.display=="block") {
+			e.style.display="none"
+ 		}else{
+			 e.style.display="block"
+		 }
+	 }
+
+
+ function setClassDisplay(which,what) {
+	 var e = document.getElementsByClassName(which);
+		 for ( var i = 0; i < e.length; i++ ){
+			 e[i].style.display=what
+			 }
+		 }
+
+
+ function loadXMLDoc(dname) {
+	 if (window.XMLHttpRequest) {
+		 xhttp=new XMLHttpRequest();
+	 }else{
+		 xhttp=new ActiveXObject("Microsoft.XMLHTTP");
+ 	}
+ 	xhttp.open("GET",dname,false);
+	xhttp.send("");
+	return xhttp.responseXML;
+ }
+
+
+ function xslt(sheet,data,dest) {
+	 var sheetName=sheet;
+	 var xmlName=data;
+	 var htmlDest=dest;
+	 // code for IE
+	 if (window.ActiveXObject) {
+		 var XML = new ActiveXObject("MSXML2.FreeThreadedDomDocument");
+		 XML.async = "false";
+		 XML.load(xmlName);
+		 var XSL = new ActiveXObject("MSXML2.FreeThreadedDomDocument");
+		 XSL.async = "false";
+		 XSL.load(sheetName);
+		 var XSLTCompiled = new ActiveXObject("MSXML2.XSLTemplate");
+		 //Add the stylesheet information
+		 XSLTCompiled.stylesheet = XSL.documentElement;
+		 //Create the XSLT processor
+		 var msSheet = XSLTCompiled.createProcessor();
+		 msSheet.input = XML
+		 //Perform the transform
+		 msSheet.transform();
+		 document.getElementById(htmlDest).innerHTML=msSheet.output;
+	 }
+	 // code for Mozilla, Firefox, Opera, etc.
+	 else if (document.implementation && document.implementation.createDocument){
+		 xsl=loadXMLDoc(sheetName);
+		 xml=loadXMLDoc(xmlName);
+		 xsltProcessor=new XSLTProcessor();
+		 xsltProcessor.importStylesheet(xsl);
+		 resultDocument = xsltProcessor.transformToFragment(xml,document);
+ 		document.getElementById(htmlDest).appendChild(resultDocument);
+	 }
+	 setClassDisplay("trace","none"); //by default allare visible to protect disabled javascript
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/report-styles/jreport.xsl	Tue May 10 11:58:19 2011 +0200
@@ -0,0 +1,215 @@
+<?xml version="1.0"?>
+<!--
+
+This file is part of IcedTea.
+
+IcedTea 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.
+
+IcedTea 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.
+
+ -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+  <xsl:template match="/">
+    <h3>Date:</h3>
+    <xsl:value-of select="/testsuite/date"/>
+    <br/>
+    <h2>Result: (<xsl:value-of select="round(sum(/testsuite/testcase/@time) div 1000)"/>s)</h2>
+    <div class="tablee">
+      <div class="row">
+        <div class="cell1">TOTAL: </div>
+        <div class="cell2">
+          <xsl:value-of select="/testsuite/stats/summary/total"/>
+        </div>
+        <div class="space-line"/>
+      </div>
+      <div class="row passed">
+        <div class="cell1">passed: </div>
+        <div class="cell2">
+          <xsl:value-of select="/testsuite/stats/summary/passed"/>
+        </div>
+        <div class="space-line"/>
+      </div>
+      <div class="row failed">
+        <div class="cell1">failed: </div>
+        <div class="cell2">
+          <xsl:value-of select="/testsuite/stats/summary/failed"/>
+        </div>
+        <div class="space-line"/>
+      </div>
+      <div class="row ignored">
+        <div class="cell1">ignored: </div>
+        <div class="cell2">
+          <xsl:value-of select="/testsuite/stats/summary/ignored"/>
+        </div>
+        <div class="space-line"/>
+      </div>
+    </div>
+    <h2>Classes:</h2>
+    <xsl:for-each select="/testsuite/stats/classes/class">
+      <div>
+        <xsl:attribute name="class">
+          <xsl:choose>
+            <xsl:when test="passed = total">
+		passed
+	      </xsl:when>
+            <xsl:otherwise>
+	        failed
+	    </xsl:otherwise>
+          </xsl:choose>
+        </xsl:attribute>
+        <a class="classSumaryName"><xsl:attribute name="href">
+    #<xsl:value-of select="@name"/>
+  </xsl:attribute><xsl:value-of select="@name"/>
+(<xsl:value-of select="@time"/>ms):
+</a>
+      </div>
+      <blockquote>
+        <div class="tablee">
+          <div class="row">
+            <div class="cell1">TOTAL: </div>
+            <div class="cell2">
+              <xsl:value-of select="total"/>
+            </div>
+            <div class="space-line"/>
+          </div>
+          <div class="row passed">
+            <div class="cell1">passed: </div>
+            <div class="cell2">
+              <xsl:value-of select="passed"/>
+            </div>
+            <div class="space-line"/>
+          </div>
+          <div class="row failed">
+            <div class="cell1">failed: </div>
+            <div class="cell2">
+              <xsl:value-of select="failed"/>
+            </div>
+            <div class="space-line"/>
+          </div>
+          <div class="row ignored">
+            <div class="cell1">ignored: </div>
+            <div class="cell2">
+              <xsl:value-of select="ignored"/>
+            </div>
+            <div class="space-line"/>
+          </div>
+        </div>
+      </blockquote>
+      <hr/>
+    </xsl:for-each>
+
+   
+    <h2>Individual results:</h2>
+    <button onclick="setClassDisplay('trace','none')">NoneTrace</button>
+    <button onclick="setClassDisplay('trace','block')">AllTraces</button>
+    <xsl:for-each select="/testsuite/testcase">
+      <div>
+        <xsl:attribute name="class">
+          <xsl:choose>
+            <xsl:when test="error">
+           failed
+            </xsl:when>
+            <xsl:otherwise>
+           passed 
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:attribute>
+        <a>
+          <xsl:attribute name="name">
+            <xsl:value-of select="normalize-space(@classname)"/>
+          </xsl:attribute>
+        </a>
+        <div class="lineHeader">
+          <div class="clazz">
+            <xsl:value-of select="@classname"/>
+          </div>
+          <xsl:text disable-output-escaping="no"> - </xsl:text>
+          <div class="method">
+            <xsl:value-of select="@name"/>
+          </div>
+        </div>
+        <div class="result">
+          <xsl:choose>
+            <xsl:when test="not(error)">
+              <div class="status">
+         PASSED (<xsl:value-of select="@time"/>s)
+         </div>
+            </xsl:when>
+            <xsl:otherwise>
+              <div class="status">
+        FAILED (<xsl:value-of select="@time"/>s)
+         </div>
+              <div class="wtrace">
+                <div class="theader">
+                  <xsl:value-of select="error/@type"/>  <xsl:text disable-output-escaping="no"> - </xsl:text>
+                  <xsl:value-of select="error/@message"/>  
+                  <button onclick="negateIdDisplay('{generate-id(error)}')">StackTrace</button>
+                </div>
+                <div class="trace" id="{generate-id(error)}">
+                  <pre>
+                    <xsl:value-of select="error"/>
+                  </pre>
+                </div>
+              </div>
+            </xsl:otherwise>
+          </xsl:choose>
+          <div class="space-line"/>
+        </div>
+        <div class="space-line"/>
+      </div>
+      <div class="space-line"/>
+    </xsl:for-each>
+
+          <div class="stbound">
+            <div class="theader stExt2">
+            STD-OUT - <button onclick="negateIdDisplay('{generate-id(/testsuite/system-out)}')">Show/hide</button>
+            </div>
+            <div class="trace stExt3" id="{generate-id(/testsuite/system-out)}">
+              <pre>
+                <xsl:value-of select="/testsuite/system-out"/>
+              </pre>
+            </div>
+          </div>
+ <div class="space-line"/>
+    <div class="stbound">
+            <div class="theader stExt2">
+            STD-ERR - <button onclick="negateIdDisplay('{generate-id(/testsuite/system-err)}')">Show/hide</button>
+            </div>
+            <div class="trace stExt3" id="{generate-id(/testsuite/system-err)}">
+              <pre>
+                <xsl:value-of select="/testsuite/system-err"/>
+              </pre>
+            </div>
+          </div>
+ <div class="space-line"/>
+
+  </xsl:template>
+</xsl:stylesheet>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/report-styles/report.css	Tue May 10 11:58:19 2011 +0200
@@ -0,0 +1,21 @@
+div.passed {background-color:green;height:auto }
+div.failed {background-color:red ;height:auto}
+div.ignored {background-color:yellow ;height:auto}
+
+div.clazz {display:inline }
+div.method {display:inline }
+
+div.result {display:block; border: thin solid black ;height:auto}
+div.status {display:inline; }
+div.wtrace {display:inline; border: thin solid black; float: right;height:auto}
+div.theader {display:block; border: thin solid black}
+div.trace {display:block; border: thin solid black}
+
+div.space-line {  clear: both; margin: 0; padding: 0; width: auto;}
+
+div.tablee {width:200px; border: thin solid black; }
+div.row { border: thin solid black; }
+div.cell1 {display:inline; float: left;height:auto}
+div.cell2 {display:inline; float: right;height:auto}
+
+a.classSumaryName{font-weight:bold}