* Patch from Graeme Geldenhuys to improve layout of generated report

git-svn-id: trunk@12328 -
This commit is contained in:
michael 2008-12-10 21:17:02 +00:00
parent d9c5cd76cd
commit 8be887e018
11 changed files with 969 additions and 211 deletions

8
.gitattributes vendored
View File

@ -1347,7 +1347,15 @@ packages/fcl-fpcunit/src/example_output/results.pdf -text
packages/fcl-fpcunit/src/example_output/results.txt svneol=native#text/plain
packages/fcl-fpcunit/src/example_xsl/fpcunit.css svneol=native#text/plain
packages/fcl-fpcunit/src/example_xsl/fpcunit.xsl svneol=native#text/plain
packages/fcl-fpcunit/src/example_xsl/images/lastlink.gif -text
packages/fcl-fpcunit/src/example_xsl/images/link.gif -text
packages/fcl-fpcunit/src/example_xsl/images/minus.gif -text
packages/fcl-fpcunit/src/example_xsl/images/plus.gif -text
packages/fcl-fpcunit/src/example_xsl/images/testcase.gif -text
packages/fcl-fpcunit/src/example_xsl/images/testsuite.gif -text
packages/fcl-fpcunit/src/example_xsl/readme.txt svneol=native#text/plain
packages/fcl-fpcunit/src/example_xsl/scripts/fpcunit.css svneol=native#text/plain
packages/fcl-fpcunit/src/example_xsl/scripts/treeview.js svneol=native#text/plain
packages/fcl-fpcunit/src/exampletests/Makefile svneol=native#text/plain
packages/fcl-fpcunit/src/exampletests/Makefile.fpc svneol=native#text/plain
packages/fcl-fpcunit/src/exampletests/fpcunittests.pp svneol=native#text/plain

View File

@ -1,82 +1,63 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"/>
<!-- Change the encoding here if you need it, i.e. UTF-8 -->
<xsl:output method="html" encoding="UTF-8" indent="yes"
doctype-public="-//W3C//DTD HTML 4.0 Transitional//EN"
/>
<!-- ************************************ Parameters ************************************ -->
<!-- expand-treeview, boolean - true if you want to expand the tree-view at the first print -->
<xsl:param name="param-expand-treeview" select="'false'"/>
<!-- preferred browser Netscape/Mozilla or Internet Explorer. Thanks to Bill, 90% of the sheeps use IE, but I don't so NS is the default here -->
<xsl:param name="param-is-netscape" select="'true'"/>
<!-- horizontal distance in pixels between a folder and its leaves -->
<xsl:param name="param-shift-width" select="15"/>
<!-- image source directory-->
<xsl:param name="param-img-directory" select="'images/'"/>
<!-- scripts and stylesheet source directory-->
<xsl:param name="param-scripts-directory" select="'scripts/'"/>
<!-- expand-errors-and-failures, boolean - true if you want to expand the testcase nodes (errors & failures) at the first print -->
<xsl:param name="param-expand-errors-and-failures" select="'false'"/>
<!-- if expand-treeview is false we can auto expand first few nodes. if 0 then expand until error or failure testcases. -->
<xsl:param name="param-expand-depth" select="3"/>
<!-- ************************************ Variables ************************************ -->
<xsl:variable name="var-simple-quote">'</xsl:variable>
<xsl:variable name="var-slash-quote">\'</xsl:variable>
<xsl:template match="/">
<html>
<head>
<title>fpcUnit Results</title>
<style type="text/css" title="fpcUnit" media="screen">
@import "fpcunit.css";
</style>
<script>
window.onload = function () {
var x = document.getElementsByTagName('div');
for (var i=0;i&lt;x.length;i++)
{
if (x[i].className == 'testsuitelabel')
x[i].onclick = clickSuite;
if (x[i].className == 'testsuiteshowall')
x[i].onclick = openSuites;
if (x[i].className == 'testsuitehideall')
x[i].onclick = closeSuites;
}
closeSuites();
}
function closeSuites()
{
var x = document.getElementsByTagName('div');
for (var i=0;i&lt;x.length;i++)
{
if (x[i].className == 'testcontent')
x[i].style.display = 'none';
}
}
function openSuites()
{
var x = document.getElementsByTagName('div');
for (var i=0;i&lt;x.length;i++)
{
if (x[i].className == 'testcontent')
x[i].style.display = 'block';
}
}
function clickSuite(e)
{
if (!e) var e = window.event;
if (e.target) var tg = e.target;
else if (e.srcElement) var tg = e.srcElement;
while (tg.nodeName != 'DIV') // Safari GRRRRRRRRRR
tg = tg.parentNode;
var nextSib = tg.nextSibling;
while (nextSib.nodeType != 1)
nextSib = nextSib.nextSibling;
var nextSibStatus = (nextSib.style.display == 'none') ? 'block' : 'none';
nextSib.style.display = nextSibStatus;
}
</script>
<title>FPCUnit Results</title>
<link href="{$param-scripts-directory}fpcunit.css" rel="stylesheet" type="text/css"/>
<script src="{$param-scripts-directory}treeview.js" language="javascript" type="text/javascript"/>
</head>
<body>
<a name="Summary"/>
<h2>fpcUnit Results</h2>
<h2>FPCUnit Results</h2>
<xsl:apply-templates/>
<address>
<a href="http://opensoft.homeip.net">fpcUnit Report</a> 0.3.1 © 2006 by
<a href="mailto:graemeg@gmail.com?subject=Comments about fpcUnit Report">Graeme Geldenhuys</a>.<br/>
Licensed under the <a href="http://www.gnu.org/copyleft/gpl.html">GNU General Public License</a>.<br/>
</address>
<address>
<a href="http://opensoft.homeip.net">FPCUnit Report</a> 0.4.0 [beta3] &#169; 2006-2008 by
<a href="mailto:graemeg@gmail.com?subject=Comments about FPCUnit Report">Graeme Geldenhuys</a>.<br/>
Licensed under the <a href="http://www.gnu.org/copyleft/gpl.html">GNU General Public License</a>.<br/>
</address>
<p align="right">
<a href="http://validator.w3.org/check?uri=referer"><img
src="http://www.w3.org/Icons/valid-html40" border="0"
alt="Valid HTML 4.0 Transitional" height="31" width="88"/></a>
</p>
</body>
</html>
</xsl:template>
<xsl:template match="TestResults">
<xsl:template name="summary" match="TestResults">
<xsl:variable name="runCount" select="NumberOfRunTests"/>
<xsl:variable name="failureCount" select="NumberOfFailures"/>
<xsl:variable name="errorCount" select="NumberOfErrors"/>
@ -85,38 +66,24 @@ function clickSuite(e)
<h3>Summary</h3>
<!-- Summary Table -->
<table border="0" rules="none" width="100%">
<tr align="left" class="title">
<th width="45%" align="left">Name</th>
<th width="7%" align="left">Tests</th>
<th width="8%" align="left">Failures</th>
<th width="8%" align="left">Errors</th>
<th width="11%" align="left">Elapsed Time</th>
<th width="14%" align="left">Run Date</th>
</tr>
<xsl:choose>
<xsl:when test="$errorCount &gt; 0">
<tr class="error">
<td>Summary</td>
<td><xsl:value-of select="$runCount"/></td>
<td><xsl:value-of select="$failureCount"/></td>
<td><xsl:value-of select="$errorCount"/></td>
<td><xsl:value-of select="$elapsedTime"/></td>
<td><xsl:value-of select="$dateRan"/></td>
<table border="0" rules="none" width="100%">
<tr align="left" class="title">
<th width="45%" align="left">Name</th>
<th width="7%" align="left">Tests</th>
<th width="8%" align="left">Failures</th>
<th width="8%" align="left">Errors</th>
<th width="11%" align="left">Elapsed Time</th>
<th width="14%" align="left">Run Date</th>
</tr>
</xsl:when>
<xsl:when test="$failureCount &gt; 0">
<tr class="failure">
<td>Summary</td>
<td><xsl:value-of select="$runCount"/></td>
<td><xsl:value-of select="$failureCount"/></td>
<td><xsl:value-of select="$errorCount"/></td>
<td><xsl:value-of select="$elapsedTime"/></td>
<td><xsl:value-of select="$dateRan"/></td>
</tr>
</xsl:when>
<xsl:otherwise>
<tr class="success">
<!-- Set class attribute based on test results -->
<xsl:if test="$failureCount &gt; 0">
<xsl:attribute name="class">failure</xsl:attribute>
</xsl:if>
<xsl:if test="$errorCount &gt; 0">
<xsl:attribute name="class">error</xsl:attribute>
</xsl:if>
<td>Summary</td>
<td><xsl:value-of select="$runCount"/></td>
<td><xsl:value-of select="$failureCount"/></td>
@ -124,136 +91,357 @@ function clickSuite(e)
<td><xsl:value-of select="$elapsedTime"/></td>
<td><xsl:value-of select="$dateRan"/></td>
</tr>
</xsl:otherwise>
</xsl:choose>
</table>
</table>
<p>Note: <i>Failures</i> are anticipated and checked for with assertions. <i>Errors</i> are
unexpected results.</p>
<hr/>
<hr/>
<xsl:call-template name="test_listing"></xsl:call-template>
<xsl:call-template name="test_listing"/>
<xsl:call-template name="test_failures"/>
<xsl:call-template name="test_errors"/>
</xsl:template>
<xsl:template name="test_listing">
<div id="testlisting">
<a name="Test_Listing"/>
<h3>Test Listing</h3>
<p>
[<a href="#Summary">Summary</a>]
[<a href="#Test_Listing">Test Listing</a>]
[<a href="#Failures">Failures</a>]
[<a href="#Errors">Errors</a>]
</p>
<!-- Test Listing Table -->
<table border="0" rules="none" width="100%">
<tr align="left" class="title">
<td align="left">Name<br/><div class="testsuiteshowall">[show all]</div><div class="testsuitehideall">[hide all]</div></td>
<td width="150" align="right">Elapsed Time<br/>(hh:mm:ss.zzz)</td>
</tr>
</table>
<xsl:for-each select="TestListing/TestSuite">
<div class="testsuitelabel"><xsl:value-of select="@Name"/></div>
<div class="testcontent">
<table border="0" cellspacing="1" width="100%">
<xsl:for-each select="./Test">
<tr class="success">
<td><xsl:value-of select="@Name"/></td>
<td width="150" align="right"><xsl:value-of select="ElapsedTime"/></td>
<!--
**********************************************************************
Represents the test suites as a treeview
**********************************************************************
-->
<xsl:template name="test_listing">
<div id="testlisting">
<a name="Test_Listing"/>
<h3>Test Listing</h3>
<!-- Treeview Start -->
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<!-- Apply the template TestSuite starting with a depth in the tree of 1-->
<xsl:call-template name="test_suite">
<xsl:with-param name="depth" select="1"/>
</xsl:call-template>
</td>
</tr>
</xsl:for-each> <!-- Test -->
</table>
<!-- Treeview End -->
</div> <!-- testlisting -->
</xsl:template>
<!--
**********************************************************************
Creates a image and text representing a test suite.
**********************************************************************
-->
<xsl:template name="test_suite" match="TestSuite">
<xsl:param name="depth"/>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<!-- If first level of depth, do not shift of $param-shift-width-->
<xsl:if test="$depth>1">
<!-- highlight the test results -->
<xsl:choose>
<xsl:when test="@NumberOfErrors &gt; 0">
<td width="{$param-shift-width}" class="error_">&#160;</td>
</xsl:when>
<xsl:when test="@NumberOfFailures &gt; 0">
<td width="{$param-shift-width}" class="failure_">&#160;</td>
</xsl:when>
<xsl:otherwise>
<td width="{$param-shift-width}">&#160;</td>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<td>
<a class="folder">
<xsl:attribute name="onclick">toggle(this)</xsl:attribute>
<!-- If the treeview is unfold, the image minus (-) is displayed-->
<xsl:if test="@expanded">
<xsl:if test="@expanded='true'">
<img src="{$param-img-directory}minus.gif" alt=""/>
</xsl:if>
<xsl:if test="@expanded='false'">
<img src="{$param-img-directory}plus.gif" alt=""/>
</xsl:if>
</xsl:if>
<xsl:if test="not(@expanded)">
<xsl:if test="$param-expand-treeview = 'true'">
<img src="{$param-img-directory}minus.gif" alt=""/>
</xsl:if>
<xsl:if test="$param-expand-treeview = 'false' or not(@expanded)">
<img src="{$param-img-directory}plus.gif" alt=""/>
</xsl:if>
</xsl:if>
<img src="{$param-img-directory}testsuite.gif" alt="">
<!-- if the attribut Name is present-->
<xsl:if test="@Name">
<!-- if Netscape / Mozilla -->
<xsl:if test="$param-is-netscape='true'">
<xsl:attribute name="title"><xsl:value-of select="@Name"/></xsl:attribute>
</xsl:if>
<!-- if Internet Explorer -->
<xsl:if test="$param-is-netscape='false'">
<xsl:attribute name="alt"><xsl:value-of select="@Name"/></xsl:attribute>
</xsl:if>
</xsl:if>
</img>
<!-- Tree node text can be decorated based on the test results -->
<xsl:choose>
<xsl:when test="@NumberOfErrors &gt; 0">
<span class="node_error"><xsl:value-of select="@Name"/></span>
</xsl:when>
<xsl:when test="@NumberOfFailures &gt; 0">
<span class="node_failure"><xsl:value-of select="@Name"/></span>
</xsl:when>
<xsl:otherwise>
<span class="node_success"><xsl:value-of select="@Name"/></span>
</xsl:otherwise>
</xsl:choose>
</a>
<!-- Shall we expand all the leaves of the treeview? No by default -->
<div>
<xsl:if test="@expanded">
<xsl:if test="@expanded='true'">
<xsl:attribute name="style">display:block;</xsl:attribute>
</xsl:if>
<!-- plus (+) otherwise-->
<xsl:if test="@expanded='false'">
<xsl:attribute name="style">display:none;</xsl:attribute>
</xsl:if>
</xsl:if>
<xsl:if test="not(@expanded)">
<xsl:if test="$param-expand-treeview = 'true'">
<xsl:attribute name="style">display:block;</xsl:attribute>
</xsl:if>
<xsl:if test="$param-expand-treeview = 'false'">
<xsl:attribute name="style">display:none;</xsl:attribute>
</xsl:if>
<!-- Auto expand any nodes containing failures or errors -->
<xsl:if test="($param-expand-treeview = 'false') and ($param-expand-depth = 0)">
<xsl:if test="@NumberOfErrors &gt; 0">
<xsl:attribute name="style">display:block;</xsl:attribute>
</xsl:if>
<xsl:if test="@NumberOfFailures &gt; 0">
<xsl:attribute name="style">display:block;</xsl:attribute>
</xsl:if>
</xsl:if>
<!-- Auto expand the first few nodes as defined by param-expand-depth -->
<xsl:if test="($param-expand-treeview = 'false') and ($param-expand-depth &gt; 0)">
<xsl:if test="($depth &lt; $param-expand-depth)">
<xsl:attribute name="style">display:block;</xsl:attribute>
</xsl:if>
</xsl:if>
</xsl:if>
<!-- Thanks to the magic of recursive calls, all the descendants of
the current folder are going to be built -->
<xsl:apply-templates name="test_suite">
<xsl:with-param name="depth" select="$depth+1"/>
</xsl:apply-templates>
<!-- print all the leaves of this folder-->
<xsl:apply-templates select="/Test"></xsl:apply-templates>
</div>
</td>
</tr>
</table>
</xsl:template>
<!--
**********************************************************************
Represents the actual test.
**********************************************************************
-->
<xsl:template match="Test">
<table border="0" cellspacing="1" cellpadding="0">
<tr>
<!-- highlight the test result -->
<xsl:choose>
<xsl:when test="@Result = 'Error'">
<td width="{$param-shift-width}" class="error_">&#160;</td>
</xsl:when>
<xsl:when test="@Result = 'Failed'">
<td width="{$param-shift-width}" class="failure_">&#160;</td>
</xsl:when>
<xsl:otherwise>
<td width="{$param-shift-width}">&#160;</td>
</xsl:otherwise>
</xsl:choose>
<td class="success">
<!-- Set class attribute based on test result -->
<xsl:if test="@Result = 'Error'">
<xsl:attribute name="class">error</xsl:attribute>
</xsl:if>
<xsl:if test="@Result = 'Failed'">
<xsl:attribute name="class">failure</xsl:attribute>
</xsl:if>
<a class="leaf">
<xsl:attribute name="onclick">toggle(this)</xsl:attribute>
<!-- if it is the last leaf, print a different image for the link to the folder-->
<xsl:choose>
<xsl:when test="($param-expand-errors-and-failures='false') and ((@Result = 'Error') or (@Result = 'Failed'))">
<img src="{$param-img-directory}plus.gif" alt=""/>
</xsl:when>
<xsl:when test="($param-expand-errors-and-failures='true') and ((@Result = 'Error') or (@Result = 'Failed'))">
<img src="{$param-img-directory}minus.gif" alt=""/>
</xsl:when>
<xsl:when test="position()=last()">
<img src="{$param-img-directory}lastlink.gif" alt=""/>
</xsl:when>
<xsl:otherwise>
<img src="{$param-img-directory}link.gif" alt=""/>
</xsl:otherwise>
</xsl:choose>
<img src="{$param-img-directory}testcase.gif" alt="">
<!-- if the attribut alt is present-->
<xsl:if test="@ElapsedTime">
<!-- if Netscape / Mozilla -->
<xsl:if test="$param-is-netscape='true'">
<xsl:attribute name="title"><xsl:value-of select="@ElapsedTime"/></xsl:attribute>
</xsl:if>
<!-- if Internet Explorer -->
<xsl:if test="$param-is-netscape='false'">
<xsl:attribute name="alt"><xsl:value-of select="@ElapsedTime"/></xsl:attribute>
</xsl:if>
</xsl:if>
</img>
<!-- Text background can be highlighted based on the test results -->
<!-- <xsl:choose>
<xsl:when test="@Result = 'Error'">
<span class="node_error"><xsl:value-of select="@Name"/></span>
</xsl:when>
<xsl:when test="@Result = 'Failed'">
<span class="node_failure"><xsl:value-of select="@Name"/></span>
</xsl:when>
<xsl:otherwise>
<span class="node_success"><xsl:value-of select="@Name"/></span>
</xsl:otherwise>
</xsl:choose>
-->
<span class="node_success"><xsl:value-of select="@Name"/></span>
</a>
<!-- Show test result if they exist -->
<xsl:choose>
<xsl:when test="@Result = 'Error'">
<xsl:call-template name="error_results"></xsl:call-template>
</xsl:when>
<xsl:when test="@Result = 'Failed'">
<xsl:call-template name="failed_results"></xsl:call-template>
</xsl:when>
</xsl:choose>
</td>
<td width="150" align="right" class="success">
<!-- Set class attribute based on test result -->
<xsl:if test="@Result = 'Error'">
<xsl:attribute name="class">error</xsl:attribute>
</xsl:if>
<xsl:if test="@Result = 'Failed'">
<xsl:attribute name="class">failure</xsl:attribute>
</xsl:if>
<xsl:value-of select="@ElapsedTime"/>
</td>
</tr>
</table>
</xsl:template>
<xsl:template name="error_results">
<div style="display:none">
<xsl:if test="$param-expand-errors-and-failures='true'">
<xsl:attribute name="style">display:block;</xsl:attribute>
</xsl:if>
<table border="0">
<!-- Error Table Body -->
<TR>
<td width="{$param-shift-width}">&#160;</td>
<TD width="200" valign="top" class="title">Message:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="Message"/></TD>
</TR>
<TR>
<td width="{$param-shift-width}">&#160;</td>
<TD valign="top" class="title">Exception Class:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="ExceptionClass"/></TD>
</TR>
<TR>
<td width="{$param-shift-width}">&#160;</td>
<TD valign="top" class="title">Exception Message:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="ExceptionMessage"/></TD>
</TR>
<TR>
<td width="{$param-shift-width}">&#160;</td>
<TD valign="top" class="title">UnitName:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="SourceUnitName"/></TD>
</TR>
<TR>
<td width="{$param-shift-width}">&#160;</td>
<TD valign="top" class="title">LineNumber:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="LineNumber"/></TD>
</TR>
<TR>
<td width="{$param-shift-width}">&#160;</td>
<TD valign="top" class="title">Method Name:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="FailedMethodName"/></TD>
</TR>
</table>
</div>
</xsl:for-each> <!-- TestSuite -->
</div> <!-- testlisting -->
</xsl:template>
</xsl:template>
<xsl:template name="failed_results">
<div style="display:none">
<xsl:if test="$param-expand-errors-and-failures='true'">
<xsl:attribute name="style">display:block;</xsl:attribute>
</xsl:if>
<xsl:template name="test_failures">
<div id="failures">
<a name="Failures"/>
<h3>Failures:</h3>
<p>
[<a href="#Summary">Summary</a>]
[<a href="#Test_Listing">Test Listing</a>]
[<a href="#Failures">Failures</a>]
[<a href="#Errors">Errors</a>]
</p>
<xsl:for-each select="ListOfFailures/Failure">
<p class="backToTop">
[<a href="#Failures">Back to top</a>]
</p>
<table>
<!-- Error Table Body -->
<TR>
<TD valign="top" class="title" width="300">Message:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="Message"/></TD>
</TR>
<TR>
<TD valign="top" class="title">Exception Class:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="ExceptionClass"/></TD>
</TR>
<TR>
<TD valign="top" class="title">Exception Message:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="ExceptionMessage"/></TD>
</TR>
</table>
</xsl:for-each>
</div> <!-- failures -->
</xsl:template>
<xsl:template name="test_errors">
<div id="errors">
<a name="Errors"/>
<h3>Errors</h3>
<p>
[<a href="#Summary">Summary</a>]
[<a href="#Test_Listing">Test Listing</a>]
[<a href="#Failures">Failures</a>]
[<a href="#Errors">Errors</a>]
</p>
<xsl:for-each select="ListOfErrors/Error">
<p class="backToTop">
[<a href="#Errors">Back to top</a>]
</p>
<table>
<!-- Error Table Body -->
<TR>
<TD valign="top" class="title" width="300">Message:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="Message"/></TD>
</TR>
<TR>
<TD valign="top" class="title">Exception Class:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="ExceptionClass"/></TD>
</TR>
<TR>
<TD valign="top" class="title">Exception Message:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="ExceptionMessage"/></TD>
</TR>
<TR>
<TD valign="top" class="title">UnitName:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="SourceUnitName"/></TD>
</TR>
<TR>
<TD valign="top" class="title">LineNumber:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="LineNumber"/></TD>
</TR>
<TR>
<TD valign="top" class="title">Method Name:</TD>
<TD valign="top" class="resultmessage"><xsl:value-of select="FailedMethodName"/></TD>
</TR>
</table>
</xsl:for-each>
</div> <!-- errors -->
</xsl:template>
<table border="0">
<!-- Error Table Body -->
<tr>
<td width="{$param-shift-width}">&#160;</td>
<td width="200" valign="top" class="title">Message:</td>
<td valign="top" class="resultmessage"><xsl:value-of select="Message"/></td>
</tr>
<tr>
<td width="{$param-shift-width}">&#160;</td>
<td valign="top" class="title">Exception Class:</td>
<td valign="top" class="resultmessage"><xsl:value-of select="ExceptionClass"/></td>
</tr>
<tr>
<td width="{$param-shift-width}">&#160;</td>
<td valign="top" class="title">Exception Message:</td>
<td valign="top" class="resultmessage"><xsl:value-of select="ExceptionMessage"/></td>
</tr>
</table>
</div>
</xsl:template>
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="from"/>
<xsl:param name="to"/>
<xsl:choose>
<xsl:when test="contains($text, $from)">
<xsl:variable name="before" select="substring-before($text, $from)"/>
<xsl:variable name="after" select="substring-after($text, $from)"/>
<xsl:variable name="prefix" select="concat($before, $to)"/>
<xsl:value-of select="$before"/>
<xsl:value-of select="$to"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$after"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

View File

@ -2,14 +2,23 @@
Sample XSLT processing
----------------------
The fpcunit.xsl and fpcunit.css demonstrates how I create a Results HTML
The fpcunit.xsl demonstrates how I create a Results HTML
page from the XML generated by my unit tests.
I use the following command line application under Linux to process the XML
file.
file. This is much faster that letting the web browser do it on the fly.
xsltproc -o index.html fpcunit.xsl results.xml
For an example of the generated HTML results have a look at:
http://opensoft.homeip.net/tiopf/fpcunit/index.html
Configuration Options:
----------------------
The new fpcunit.xsl file has many configuration option. Have a look at
the beginning of the fpcunit.xsl file. All options are listed and
has associated comments.
Graeme Geldenhuys.
graemeg@gmail.com

View File

@ -0,0 +1,174 @@
body
{
font-family: verdana, arial, helvetica, Sans-Serif;
font-size: x-small;
background: #FFFFFF;
}
a
{
text-decoration: none;
background-color: Transparent
}
a:link
{
color: #0033ff;
}
a:visited
{
color: #003399;
}
a:active, a:hover
{
color:#69c;
}
h2
{
padding: 4px 4px 4px 6px;
font-size: large;
border: 1px solid black;
font-weight: bold;
color: white;
background-color: #006699;
}
h3
{
padding: 4px 4px 4px 6px;
border: 1px solid #003399;
color: #FFFFFF;
background-color: #0099CC;
font-weight: normal;
font-size: medium;
}
table
{
padding:0px;
width: 100%;
margin-left: -2px;
margin-right: -2px;
}
th, td
{
padding: 2px 4px 2px 4px;
vertical-align: top;
font-size: x-small;
}
address
{
font-family: verdana, arial, helvetica, Sans-Serif;
font-size: 8pt;
font-style: normal;
text-align: right;
}
.title
{
background-color: #bbb;
color: white;
}
.resultmessage
{
background-color: #D3E4FF;
}
.success
{
background-color: lightgreen;
color: black;
}
.node_success
{
cursor:pointer; cursor:hand; /* cross browser hack */
}
.failure
{
background-color: #C100C1;
color: black;
}
.node_failure
{
color: #C100C1;
cursor:pointer; cursor:hand; /* cross browser hack */
}
.notrun
{
background-color: yellow;
color: black;
}
.error
{
background-color: red;
color: black;
font-size: 9pt;
}
.node_error
{
color: red;
cursor:pointer; cursor:hand; /* cross browser hack */
}
.right
{
font-size: 8pt;
text-align: right;
}
.backToTop
{
text-align: right;
}
.testsuitelabel
{
background-color: cadetblue;
color: black;
cursor:pointer; cursor:hand; /* cross browser hack */
padding-top: 3px;
border: 1px solid #F5F5F5;
}
.testsuiteshowall
{
display:inline;
cursor:pointer; cursor:hand; /* cross browser hack */
}
.testsuitehideall
{
display:inline;
cursor:pointer; cursor:hand; /* cross browser hack */
}
div.testcontent {
margin-left: 8px;
}
/* Customize the "folder" style here */
a.folder { font-family: arial;
font-size: 9pt;
padding:0px;
font-family : cursive;
}
/* Customize the "leaf" style here */
a.leaf {
font-family: cursive;
padding:0px;
cursor:pointer; cursor:hand; /* cross browser hack */
font-size : 9pt;
}

View File

@ -0,0 +1,379 @@
// ---------------------------------------------------------------------------
// --- Name: Easy DHTML Treeview --
// --- Original idea by : D.D. de Kerf --
// --- Updated by Jean-Michel Garnier, garnierjm@yahoo.fr --
// ---------------------------------------------------------------------------
/*****************************************************************************
Name : toggle
Parameters : node , DOM element (<a> tag)
Description : Description, collapse or unfold a branch
Author : Jean-Michel Garnier / D.D. de Kerf
*****************************************************************************/
function toggle(node) {
// Get the next tag (read the HTML source)
var nextDIV = node.nextSibling;
// find the next DIV
while(nextDIV.nodeName != "DIV") {
nextDIV = nextDIV.nextSibling;
}
// Unfold the branch if it isn't visible
if (nextDIV.style.display == 'none') {
// Change the image (if there is an image)
if (node.childNodes.length > 0) {
if (node.childNodes.item(0).nodeName == "IMG") {
node.childNodes.item(0).src = getImgDirectory(node.childNodes.item(0).src) + "minus.gif";
}
}
nextDIV.style.display = 'block';
}
// Collapse the branch if it IS visible
else {
// Change the image (if there is an image)
if (node.childNodes.length > 0) {
if (node.childNodes.item(0).nodeName == "IMG") {
node.childNodes.item(0).src = getImgDirectory(node.childNodes.item(0).src) + "plus.gif";
}
}
nextDIV.style.display = 'none';
}
}
/*****************************************************************************
Name : toggle2
Parameters : node DOM element (<a> tag), folderCode String
Description : if you use the "code" attribute in a folder element, toggle2 is called
instead of toggle. The consequence is that you MUST implement a selectFolder function in your page.
Author : Jean-Michel Garnier
*****************************************************************************/
function toggle2(node, folderCode) {
toggle(node);
selectFolder(folderCode);
}
/*****************************************************************************
Name : getImgDirectory
Parameters : Image source path
Return : Image source Directory
Author : Jean-Michel Garnier
*****************************************************************************/
function getImgDirectory(source) {
return source.substring(0, source.lastIndexOf('/') + 1);
}
/************************************
************* IMPORTANT *************
*************************************
The functions above are NOT used by the DHTML treeview. Netherless, have a look bc some be useful if you
need to make XSLT on the client (since IE 5.5 and soon Mozilla !)
*/
/*****************************************************************************
Name : stringExtract
Parameters :
- st String input string, contains n separators
- position int, from 0 to n, position of the token wanted
- separator char, separator between token
Return : the token at the position wanted if it exists
Description : Equivalent to class java.util.StringTokenizer
Example -> stringExtract("A; B; C", 0, ";") = "A"
Author : Jean-Michel Garnier
*****************************************************************************/
function stringExtract( st, position, separator ) {
var array;
var result = new String('');
var s = new String(st);
if (s != '' ) {
array = s.split( separator);
// @TODO, add a control on position value ...
result = array[position];
}
return result;
}
/*****************************************************************************
Name : jsTrim
Parameters : value, String
Return : the same String, with space characters removed
Description : equivalent to trim function
Author : Jean-Michel Garnier
*****************************************************************************/
function jsTrim(value) {
var result = "";
for (i=0; i < value.length; i++) {
if (value.charAt(i) != ' ') {
result += value.charAt(i);
}
}
return result;
}
/*****************************************************************************
Name : findObj
Parameters :
- n String object's name
- d Document document
Return : a reference on the object if it exists
Description : Search an object in a document from its name.
Author : Macromedia
*****************************************************************************/
function findObj(n, d) {
var p, i, x;
if (!d)
d = document;
if ( (p=n.indexOf("?") )>0 && parent.frames.length ) {
d = parent.frames[n.substring(p+1)].document;
n = n.substring(0,p);
}
if (!(x=d[n])&& d.all )
x = d.all[n];
for (i=0; !x && i < d.forms.length; i++)
x = d.forms[i][n];
for (i=0; !x && d.layers && i<d.layers.length; i++)
x = findObj(n, d.layers[i].document);
return x;
}
/*****************************************************************************
Name : isInSelectInput
Parameters :
- v String Option value
- select_input input SELECT
Return : true if the SELECT already value
Author : Jean-Michel Garnier
*****************************************************************************/
function isInSelectInput(v, select_input) {
for(var i=0; i<select_input.options.length; i++) {
if (select_input.options[i].value == v) {
return true;
}
}
return false;
}
/*****************************************************************************
Name : selectOption
Parameters :
- v_value String Option value
- select_input SELECT
Description : Select all options whose value
Author : Jean-Michel Garnier
*****************************************************************************/
function selectOption(v_value, select_input) {
var i, nb_item;
nb_item = select_input.options.length;
for (i = 0; i < nb_item ; i++) {
if ( select_input.options[i].value == v_value )
select_input.options[i].selected = true;
}
}
/*****************************************************************************
Name : selectRemoveSelectedOption
Parameters : select_input SELECT
Description : removes all the selected options
Author : Jean-Michel Garnier
*****************************************************************************/
function selectRemoveSelectedOption(select_input) {
for(var i=0; i<select_input.options.length; i++) {
if ( select_input.options[i].selected ) {
select_input.options[i] = null;
}
}
select_input.selectedIndex = -1;
}
/*****************************************************************************
Name : selectRemoveAll
Parameters : select_input
Description : This Function removes all options
Author : Jean-Michel Garnier
*****************************************************************************/
function selectRemoveAll(select_input) {
var linesNumber = select_input.options.length;
for(i=0; i < linesNumber; i++) {
select_input.options[0] = null;
}
select_input.selectedIndex = -1;
}
/*****************************************************************************
Name : buildXMLSource
Parameters : xmlSource_name, String, can be a file name (.xml or .xslt) or
a String containing the xml
!!!BE SURE xml and xlt are lowercase
Return : a reference on a ActiveX Msxml2.FreeThreadedDOMDocument with the xml loaded
Author : Jean-Michel Garnier
*****************************************************************************/
function buildXMLSource(xmlSource_name) {
var obj, file_extension;
obj = new ActiveXObject("Msxml2.FreeThreadedDOMDocument");
obj.async = false;
obj.resolveExternals = false;
file_extension = stringExtract(xmlSource_name, 1, ".");
// if there is a file extension, then load the file
if (file_extension == "xml" || file_extension == "xslt" ) {
obj.load(xmlSource_name);
}
else {
// else load the XML String
obj.loadXML(xmlSource_name);
}
return obj;
}
/*****************************************************************************
Name : transform
Parameters :
- xmlSource Msxml2.FreeThreadedDOMDocument ActiveX XML
- xsltSource Msxml2.FreeThreadedDOMDocument ActiveX XSLT
Return : String with the result of the transformation (not an ActiveX object !)
Description :
Author : Jean-Michel Garnier
*****************************************************************************/
function transform(xmlSource, xsltSource) {
var xslt;
var xslProc, paramName, paramValue;
// Create XLST
xslt = new ActiveXObject("Msxml2.XSLTemplate");
xslt.stylesheet = xsltSource;
// Add parameters
xslProc = xslt.createProcessor();
xslProc.input = xmlSource;
// add parameters if present
if (arguments.length >2 && arguments.length % 2 == 0){
for (var i=0; i < Math.floor((arguments.length)/2)-1; i++){
paramName = arguments[2*i+2];
paramValue = arguments[2*i+3];
xslProc.addParameter(paramName, paramValue);
}
}
xslProc.transform();
return xslProc.output;
}
function BrowserDetectLite() {
var ua = navigator.userAgent.toLowerCase();
// browser name
this.isGecko = (ua.indexOf('gecko') != -1);
this.isMozilla = (this.isGecko && ua.indexOf("gecko/") + 14 == ua.length);
this.isNS = ( (this.isGecko) ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) );
this.isIE = ( (ua.indexOf("msie") != -1) && (ua.indexOf("opera") == -1) && (ua.indexOf("webtv") == -1) );
this.isOpera = (ua.indexOf("opera") != -1);
this.isKonqueror = (ua.indexOf("konqueror") != -1);
this.isIcab = (ua.indexOf("icab") != -1);
this.isAol = (ua.indexOf("aol") != -1);
this.isWebtv = (ua.indexOf("webtv") != -1);
// spoofing and compatible browsers
this.isIECompatible = ( (ua.indexOf("msie") != -1) && !this.isIE);
this.isNSCompatible = ( (ua.indexOf("mozilla") != -1) && !this.isNS && !this.isMozilla);
// browser version
this.versionMinor = parseFloat(navigator.appVersion);
// correct version number
if (this.isNS && this.isGecko) {
this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) );
}
else if (this.isIE && this.versionMinor >= 4) {
this.versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) );
}
else if (this.isMozilla) {
this.versionMinor = parseFloat( ua.substring( ua.indexOf('rv:') + 3 ) );
}
else if (this.isOpera) {
if (ua.indexOf('opera/') != -1) {
this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera/') + 6 ) );
}
else {
this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera ') + 6 ) );
}
}
else if (this.isKonqueror) {
this.versionMinor = parseFloat( ua.substring( ua.indexOf('konqueror/') + 10 ) );
}
else if (this.isIcab) {
if (ua.indexOf('icab/') != -1) {
this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab/') + 6 ) );
}
else {
this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab ') + 6 ) );
}
}
else if (this.isWebtv) {
this.versionMinor = parseFloat( ua.substring( ua.indexOf('webtv/') + 6 ) );
}
this.versionMajor = parseInt(this.versionMinor);
this.geckoVersion = ( (this.isGecko) ? ua.substring( (ua.lastIndexOf('gecko/') + 6), (ua.lastIndexOf('gecko/') + 14) ) : -1 );
// dom support
this.isDOM1 = (document.getElementById);
this.isDOM2Event = (document.addEventListener && document.removeEventListener);
// css compatibility mode
this.mode = document.compatMode ? document.compatMode : 'BackCompat';
// platform
this.isWin = (ua.indexOf('win') != -1);
this.isWin32 = (this.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1 || ua.indexOf('xp') != -1) );
this.isMac = (ua.indexOf('mac') != -1);
this.isUnix = (ua.indexOf('unix') != -1 || ua.indexOf('linux') != -1 || ua.indexOf('sunos') != -1 || ua.indexOf('bsd') != -1 || ua.indexOf('x11') != -1)
// specific browser shortcuts
this.isNS4x = (this.isNS && this.versionMajor == 4);
this.isNS40x = (this.isNS4x && this.versionMinor < 4.5);
this.isNS47x = (this.isNS4x && this.versionMinor >= 4.7);
this.isNS4up = (this.isNS && this.versionMinor >= 4);
this.isNS6x = (this.isNS && this.versionMajor == 6);
this.isNS6up = (this.isNS && this.versionMajor >= 6);
this.isNS7x = (this.isNS && this.versionMajor == 7);
this.isNS7up = (this.isNS && this.versionMajor >= 7);
this.isIE4x = (this.isIE && this.versionMajor == 4);
this.isIE4up = (this.isIE && this.versionMajor >= 4);
this.isIE5x = (this.isIE && this.versionMajor == 5);
this.isIE55 = (this.isIE && this.versionMinor == 5.5);
this.isIE5up = (this.isIE && this.versionMajor >= 5);
this.isIE6x = (this.isIE && this.versionMajor == 6);
this.isIE6up = (this.isIE && this.versionMajor >= 6);
this.isIE4xMac = (this.isIE4x && this.isMac);
}