bodewig     01/02/02 09:04:03

  Modified:    .        WHATSNEW build.xml
               src/main/org/apache/tools/ant/taskdefs defaults.properties
               src/main/org/apache/tools/ant/util DOMElementWriter.java
  Added:       src/main/org/apache/tools/ant/taskdefs/optional/junit
                        AggregateTransformer.java XMLResultAggregator.java
               src/main/org/apache/tools/ant/taskdefs/optional/junit/html
                        index.html stylesheet.css
               src/main/org/apache/tools/ant/taskdefs/optional/junit/xsl
                        all-classes.xsl all-packages.xsl class-details.xsl
                        classes-list.xsl overview-packages.xsl
                        overview-summary.xsl package-summary.xsl
                        toolkit.xsl
  Log:
  New task <junitreport> and some improvements of DOMElementWriter
  
  Submitted by: Stephane Bailliez <[EMAIL PROTECTED]>
  
  Revision  Changes    Path
  1.74      +1 -1      jakarta-ant/WHATSNEW
  
  Index: WHATSNEW
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/WHATSNEW,v
  retrieving revision 1.73
  retrieving revision 1.74
  diff -u -r1.73 -r1.74
  --- WHATSNEW  2001/02/01 17:14:03     1.73
  +++ WHATSNEW  2001/02/02 17:03:49     1.74
  @@ -22,7 +22,7 @@
   * A GUI Frontend: Antidote. This is currently in development.
   
   * New tasks: stylebook, propertyfile, depend, antlr, telnet, csc,
  -  ilasm, apply, javah, several clearcase tasks
  +  ilasm, apply, javah, several clearcase tasks, junitreport
   
   * Added output attribute to <java>.
   
  
  
  
  1.127     +12 -0     jakarta-ant/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/build.xml,v
  retrieving revision 1.126
  retrieving revision 1.127
  diff -u -r1.126 -r1.127
  --- build.xml 2001/02/01 15:46:26     1.126
  +++ build.xml 2001/02/02 17:03:50     1.127
  @@ -193,6 +193,10 @@
         <exclude name="${optional.package}/ide/VAJ*.java" unless="vaj.present" 
/>
         <exclude name="${optional.package}/perforce/*.java" 
unless="jakarta.oro.present" />
         <exclude name="${optional.package}/sound/*.java" unless="jmf.present" 
/>
  +      <exclude name="${optional.package}/junit/XMLResultAggregator.java"
  +               unless="trax.present" />
  +      <exclude name="${optional.package}/junit/AggregateTransformer.java"
  +               unless="trax.present" />
       </javac>
       
       <copy todir="${build.classes}">
  @@ -212,6 +216,14 @@
           <include name="**/defaultManifest.mf" />
         </fileset>
       </copy>
  +
  +    <copy todir="${build.classes}/${optional.package}/junit">
  +       <fileset dir="${java.dir}/${optional.package}/junit">
  +         <include name="html/**" />
  +         <include name="xsl/**" />
  +       </fileset>
  +    </copy>
  +
     </target>
     
     <!-- 
  
  
  
  1.61      +1 -0      
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties
  
  Index: defaults.properties
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/defaults.properties,v
  retrieving revision 1.60
  retrieving revision 1.61
  diff -u -r1.60 -r1.61
  --- defaults.properties       2001/02/01 15:04:41     1.60
  +++ defaults.properties       2001/02/02 17:03:54     1.61
  @@ -87,6 +87,7 @@
   cccheckin=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckin
   ccuncheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCUnCheckout
   sound=org.apache.tools.ant.taskdefs.optional.sound.SoundTask
  +junitreport=org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator
   
   # deprecated ant tasks (kept for back compatibility)
   javadoc2=org.apache.tools.ant.taskdefs.Javadoc
  
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java
  
  Index: AggregateTransformer.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2000 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.junit;
  
  import org.apache.tools.ant.Task;
  import org.apache.tools.ant.Project;
  import org.apache.tools.ant.BuildException;
  
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileOutputStream;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.io.FileNotFoundException;
  import java.io.IOException;
  
  import java.util.Enumeration;
  import java.util.Hashtable;
  
  import javax.xml.transform.Transformer;
  import javax.xml.transform.TransformerFactory;
  import javax.xml.transform.stream.StreamSource;
  import javax.xml.transform.stream.StreamResult;
  import javax.xml.transform.dom.DOMSource;
  import javax.xml.transform.TransformerConfigurationException;
  import javax.xml.transform.TransformerException;
  
  import javax.xml.parsers.DocumentBuilderFactory;
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.ParserConfigurationException;
  
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  import org.w3c.dom.NamedNodeMap;
  
  import org.xml.sax.SAXException;
  
  /**
   * Transform a JUnit xml report.
   * The default transformation generates an html report in either framed or 
non-framed
   * style. The non-framed style is convenient to have a concise report via 
mail, the
   * framed report is much more convenient if you want to browse into different
   * packages or testcases since it is a Javadoc like report.
   * In the framed report, there are 3 frames:
   * <ul>
   *  <li>packageListFrame - list of all packages.
   *  <li>classListFrame - summary of all testsuites belonging to a package or 
tests list.
   *  <li>classFrame - details of all tests made for a package or for a 
testsuite.
   * </ul>
   * As a default, the transformer will use its default stylesheets, they may 
not be
   * be appropriate for users who wants to customize their reports, so you can 
indicates
   * your own stylesheets by using <tt>setStyleDir()</tt>.
   * Stylesheets must be as follows:
   * <ul>
   *   <li><b>all-packages.xsl</b> create the package list. It creates
   *   all-packages.html file in the html folder and it is load in the 
packageListFrame</li>
   *   <li><b>all-classes.xsl</b> creates the class list. It creates the 
all-classes.html
   * file in the html folder is loaded by the 'classListFrame' frame</li>
   *   <li><b>overview-packages.xsl</b> allows to get summary on all tests made
   *   for each packages and each class that not include in a package. The 
filename
   *   is overview-packages.html</li>
   *   <li><b>class-detail.xsl</b> is the style for the detail of the tests 
made on a class.
   *   the Html resulting page in write in the directory of the package and the 
name
   *   of this page is the name of the class with "-detail" element. For 
instance,
   *   the style is applied on the MyClass testsuite, the resulting filename is
   *   <u>MyClass-detail.html</u>. This file is load in the "classFrame" 
frame.</li>
   *   <li><b>package-summary.xsl</b> allows to create a summary on the package.
   *   The resulting html file is write in the package directory. The name of 
this
   *   file is <u>package-summary.html</u> This file is load in the 
"classFrame" frame.</li>
   *   <li><b>classes-list.xsl</b> create the list of the class in this package.
   *   The resulting html file is write in the package directory and it is load 
in
   *   the 'classListFrame' frame. The name of the resulting file is 
<u>class-list.html</u></li>
   * <li>
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Stephane Bailliez</a>
   * @author <a href="mailto:[EMAIL PROTECTED]">Nicolas Delahaye</a>
   */
  public class AggregateTransformer {     
          
      public final static String ALLPACKAGES = "all-packages";
          
      public final static String ALLCLASSES = "all-classes";
          
      public final static String OVERVIEW_PACKAGES = "overview-packages";
          
      public final static String CLASS_DETAILS = "class-details";
          
      public final static String CLASSES_LIST = "classes-list";
          
      public final static String PACKAGE_SUMMARY = "package-summary";
          
      public final static String OVERVIEW_SUMMARY = "overview-summary";
  
      public final static String FRAMES = "frames";
  
      public final static String NOFRAMES = "noframes";
  
      /** Task */
      protected Task task;
  
      /** the xml document to process */
      protected Document document;
  
      /** the style directory. XSLs should be read from here if necessary */
      protected File styleDir;
  
      /** the destination directory, this is the root from where html should be 
generated */
      protected File toDir;
  
      /** the format to use for the report. Must be <tt>FRAMES</tt> or 
<tt>NOFRAMES</tt> */
      protected String format;
  
      /** the file extension of the generated files. As a default it will be 
<tt>.html</tt> */
      protected String extension;
  
      /** XML Parser factory */
      protected static final DocumentBuilderFactory dbfactory = 
DocumentBuilderFactory.newInstance();
  
      /** XSL Parser factory */
      protected static final TransformerFactory tfactory = 
TransformerFactory.newInstance();
  
      public AggregateTransformer(Task task){
          this.task = task;
      }
  
      public void setFormat(String format){
          this.format = format;
      }
  
      public void setXmlDocument(Document doc){
          this.document = doc;
      }
  
      /**
       * Set the xml file to be processed. This is a helper if you want
       * to set the file directly. Much more for testing purposes.
       * @param xmlfile xml file to be processed
       */
      void setXmlfile(File xmlfile) throws BuildException {
          try {
              setXmlDocument(readDocument(xmlfile));
          } catch (Exception e){
              throw new BuildException("Error while parsing document: " + 
xmlfile, e);
          }
      }
  
      /**
       * set the style directory. It is optional and will override the
       * default xsl used.
       * @param styledir  the directory containing the xsl files if the user
       * would like to override with its own style.
       */
      public void setStyledir(File styledir){
          this.styleDir = styledir;
      }
  
      /** set the destination directory */
      public void setTodir(File todir){
          this.toDir = todir;
      }
  
      /** set the extension of the output files */
      public void setExtension(String ext){
          this.extension = ext;
      }
  
      /** get the extension, if it is null, it will use .html as the default */
      protected String getExtension(){
          if (extension == null) {
              extension = ".html";
          }
          return extension;
      }
  
      public void transform() throws BuildException {
          checkOptions();
          try {
              Element root = document.getDocumentElement();
                          
              if (NOFRAMES.equals(format)) {
                  //createCascadingStyleSheet();
                  createSinglePageSummary(root);
              } else {
                  createFrameStructure();
                  createCascadingStyleSheet();
                  createPackageList(root);
                  createClassList(root);
                  createPackageOverview(root);
                  createAllTestSuiteDetails(root);
                  createAllPackageDetails(root);
              }
          } catch (Exception e){
              e.printStackTrace();
              throw new BuildException("Errors while applying transformations", 
e);
          }
      }
  
      /** check for invalid options */
      protected void checkOptions() throws BuildException {
          if ( !FRAMES.equals(format) && !NOFRAMES.equals(format)) {
              throw new BuildException("Invalid format. Must be 'frames' or 
'noframes' but was: '" + format + "'");
          }
          // set the destination directory relative from the project if needed.
          if (toDir == null) {
              toDir = task.getProject().resolveFile(".");
          } else if ( !toDir.isAbsolute() ) {
              toDir = task.getProject().resolveFile(toDir.getPath());
          }
          // create the directories if needed
          if (!toDir.exists()) {
              if (!toDir.mkdirs()){
                  throw new BuildException("Could not create directory " + 
toDir);
              }
          }
      }
  
      /** create a single page summary */
      protected void createSinglePageSummary(Element root) throws IOException, 
TransformerException {
          transform(root, OVERVIEW_SUMMARY + ".xsl", OVERVIEW_SUMMARY + 
getExtension());
      }
  
      /**
       * read the xml file that should be the resuiting file of the testcase.
       * @param filename name of the xml resulting file of the testcase.
       */
      protected Document readDocument(File file) throws IOException, 
SAXException, ParserConfigurationException {
          DocumentBuilder builder = dbfactory.newDocumentBuilder();
          InputStream in = new FileInputStream(file);
          try {
              return builder.parse(in);
          } finally {
              in.close();
          }
      }
  
      protected void createCascadingStyleSheet() throws IOException, 
TransformerException {
          if (styleDir == null) {
              InputStream in = getResourceAsStream("html/stylesheet.css");
              OutputStream out = new FileOutputStream( new File(toDir, 
"stylesheet.css"));
              copy(in, out);              
          }
      }
  
      protected void createFrameStructure() throws IOException, 
TransformerException{
          if (styleDir == null) {
              InputStream in = getResourceAsStream("html/index.html");
              OutputStream out = new FileOutputStream( new File(toDir, 
"index.html") );
              copy(in, out);
          }
      }
          
      /**
       * Create the list of all packages.
       * @param root root of the xml document.
       */
      protected void createPackageList(Node root) throws TransformerException {
          transform(root, ALLPACKAGES + ".xsl", ALLPACKAGES + getExtension());
      }
  
      /**
       * Create the list of all classes.
       * @param root root of the xml document.
       */
      protected void createClassList(Node root) throws TransformerException {
          transform(root, ALLCLASSES + ".xsl", ALLCLASSES + getExtension());
      }
  
      /**
       * Create the summary used in the overview.
       * @param root root of the xml document.
       */
      protected void createPackageOverview(Node root) throws 
TransformerException {
          transform(root,  OVERVIEW_PACKAGES + ".xsl", OVERVIEW_PACKAGES + 
getExtension());
      }
  
      /**
       *  @return the list of all packages that exists defined in testsuite 
nodes
       */
      protected Enumeration getPackages(Element root){
          Hashtable map = new Hashtable();
          NodeList testsuites = 
root.getElementsByTagName(XMLConstants.TESTSUITE);
          final int size = testsuites.getLength();
          for (int i = 0; i < size; i++){
              Element testsuite = (Element) testsuites.item(i);
              String packageName = 
testsuite.getAttribute(XMLConstants.ATTR_PACKAGE);
              if (packageName == null){
                  //@todo replace the exception by something else
                  throw new IllegalStateException("Invalid 'testsuite' node: 
should contains 'package' attribute");
              }
              map.put(packageName, packageName);
          }
          return map.keys();
      }
  
      /**
       * create all resulting html pages for all testsuites.
       * @param root should be 'testsuites' node.
       */
      protected void createAllTestSuiteDetails(Element root) throws 
TransformerException {
          NodeList testsuites = 
root.getElementsByTagName(XMLConstants.TESTSUITE);
          final int size = testsuites.getLength();
          for (int i = 0; i < size; i++){
              Element testsuite = (Element) testsuites.item(i);
              createTestSuiteDetails(testsuite);
          }
      }
  
      /**
       * create the html resulting page of one testsuite.
       * @param root should be 'testsuite' node.
       */
      protected void createTestSuiteDetails(Element testsuite) throws 
TransformerException {
                  
          String packageName = 
testsuite.getAttribute(XMLConstants.ATTR_PACKAGE);         
          String pkgPath = packageToPath(packageName);
          
          // get the class name
          String name = testsuite.getAttribute(XMLConstants.ATTR_NAME);
  
          // get the name of the testsuite and create the filename of the ouput 
html page
          String filename = name + "-details" + getExtension();
          String fullpathname = pkgPath + filename; // there's already end path 
separator to pkgPath
  
          // apply the style on the document.
          transform(testsuite, CLASS_DETAILS + ".xsl", fullpathname);
      }
  
      /**
       * create the html resulting page of the summary of each package of the 
root element.
       * @param root should be 'testsuites' node.
       */
      protected void createAllPackageDetails(Element root) throws 
TransformerException, ParserConfigurationException {
          Enumeration packages = getPackages(root);
          while ( packages.hasMoreElements() ){
              String pkgname = (String)packages.nextElement();
              // for each package get the list of its testsuite.
              DOMUtil.NodeFilter pkgFilter = new PackageFilter(pkgname);
              NodeList testsuites = DOMUtil.listChildNodes(root, pkgFilter, 
false);
              Element doc = buildDocument(testsuites);
              // skip package details if the package does not exist (root 
package)
              if( !pkgname.equals("") ){
                  createPackageDetails(doc, pkgname);
              }
          }
      }
  
      protected String packageToPath(String pkgname){
          if (!pkgname.equals("")) {
              return pkgname.replace('.', File.separatorChar) + 
File.separatorChar;
          }
          return "." + File.separatorChar;
      }
  
      /**
       * create the html resulting page of the summary of a package .
       * @param root should be 'testsuites' node.
       * @param pkgname Name of the package that we want a summary.
       */
      protected void createPackageDetails(Node root, String pkgname) throws 
TransformerException {
          String path = packageToPath(pkgname);
  
          // apply style to get the list of the classes of this package and
          // display it in the classListFrame.
          transform(root, CLASSES_LIST + ".xsl", path + CLASSES_LIST + 
getExtension());
  
          // apply style to get a summary on this package.
          transform(root, PACKAGE_SUMMARY + ".xsl", path + PACKAGE_SUMMARY + 
getExtension());
      }
  
      /**
       * Create an element root ("testsuites")
       * and import all nodes as children of this element.
       *
       */
      protected Element buildDocument(NodeList list) throws 
ParserConfigurationException {
          DocumentBuilder builder = dbfactory.newDocumentBuilder();
          Document doc = builder.newDocument();
          Element elem = doc.createElement(XMLConstants.TESTSUITES);
          final int len = list.getLength();
          for(int i=0 ; i < len ; i++) {
              DOMUtil.importNode(elem, list.item(i));
          }
          return elem;
      }
  
      /**
       * Apply a template on a part of the xml document.
       *
       * @param root root of the document fragment
       * @param xslfile style file
       * @param outfilename filename of the result of the style applied on the 
Node
       *
       * @throws TransformerException SAX Parsing Error on the style Sheet.
       */
      protected void transform(Node root, String xslname, String htmlname) 
throws TransformerException {
          try{
              final long t0 = System.currentTimeMillis();
              StreamSource xsl_source = getXSLStreamSource(xslname);
              Transformer transformer = tfactory.newTransformer(xsl_source);
              File htmlfile = new File(toDir, htmlname);
              // create the directory if it does not exist
              File dir = new File(htmlfile.getParent()); // getParentFile is in 
JDK1.2+
              if (!dir.exists()) {
                  dir.mkdirs();
              }
              task.log("Applying '" + xslname + "'. Generating '" + htmlfile + 
"'", Project.MSG_VERBOSE);
              transformer.transform( new DOMSource(root), new 
StreamResult(htmlfile));
              final long dt = System.currentTimeMillis() - t0;
              task.log("Transform time: " + dt + "ms");
          } catch (IOException e){
              task.log(e.getMessage(), Project.MSG_ERR);
              e.printStackTrace(); //@todo bad, change this
              throw new TransformerException(e.getMessage());
          }
      }
  
      /**
       * default xsls are embedded in the distribution jar. As a default we 
will use
       * them, otherwise we will get the one supplied by the client in a given
       * directory. It must have the same name.
       */
      protected StreamSource getXSLStreamSource(String name) throws IOException 
{
          InputStream in;
          String systemId; //we need this because there are references in xsls
          if (styleDir == null){
              in = getResourceAsStream("xsl/" + name);
              systemId = getClass().getResource("xsl/" + name).toString();
          } else {
              File f = new File(styleDir, name);
              in= new FileInputStream(f);
              systemId = f.getAbsolutePath();
          }
          StreamSource ss =  new StreamSource(in);
          ss.setSystemId(systemId);
          return ss;
      }
  
      private InputStream getResourceAsStream(String name) throws 
FileNotFoundException {
          InputStream in = getClass().getResourceAsStream(name);
          if (in == null) {
              throw new FileNotFoundException("Could not find resource '" + 
name + "'");
          }
          return in;
      }
  
      /** Do some raw stream copying */
      private static void copy(InputStream in, OutputStream out) throws 
IOException {
          int size = -1;
          byte[] buffer =  new byte[1024];
          // Make the copy
          while( (size = in.read(buffer)) != -1){
              out.write(buffer,0,size);
          }
      }
  
  
      /**
       * allow us to check if the node is a object of a specific package.
       */
      protected static class PackageFilter implements DOMUtil.NodeFilter {
          private final String pkgName;
  
          PackageFilter(String pkgname) {
              this.pkgName = pkgname;
          }
          /**
           * if the node receive is not a element then return false
           * check if the node is a class of this package.
           */
          public boolean accept(Node node) {
              String pkgname = DOMUtil.getNodeAttribute(node, 
XMLConstants.ATTR_PACKAGE);
              return pkgName.equals(pkgname);
          }
      }
  }
  
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java
  
  Index: XMLResultAggregator.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact [EMAIL PROTECTED]
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.tools.ant.taskdefs.optional.junit;
  
  import java.io.File;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.PrintWriter;
  import java.io.FileOutputStream;
  import java.util.Enumeration;
  import java.util.Vector;
  
  import org.w3c.dom.Element;
  import org.w3c.dom.Document;
  import org.w3c.dom.Node;
  import org.w3c.dom.*;
  import org.xml.sax.SAXException;
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  import org.apache.tools.ant.Project;
  import org.apache.tools.ant.Task;
  import org.apache.tools.ant.DirectoryScanner;
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.types.FileSet;
  import org.apache.tools.ant.util.DOMElementWriter;
  
  
  /**
   * This is an helper class that will aggregate all testsuites under a specific
   * directory and create a new single document. It is not particulary clean but
   * should be helpful while I am thinking about another technique.
   *
   * The main problem is due to the fact that a JVM can be forked for a testcase
   * thus making it impossible to aggregate all testcases since the listener is
   * (obviously) in the forked JVM. A solution could be to write a
   * TestListener that will receive events from the TestRunner via sockets. This
   * is IMHO the simplest way to do it to avoid this file hacking thing.
   *
   * @author <a href="mailto:[EMAIL PROTECTED]">Stephane Bailliez</a>
   */
  public class XMLResultAggregator extends Task implements XMLConstants {
      
      /** the list of all filesets, that should contains the xml to aggregate */
      protected Vector filesets = new Vector();
      
      /** the name of the result file */
      protected String toFile;
      
      /** the directory to write the file to */
      protected File toDir;
      
      protected Vector transformers = new Vector();
      
      /** the default directory: <tt>.</tt>. It is resolved from the project 
directory */
      public final static String DEFAULT_DIR = ".";
      
      /** the default file name: <tt>TESTS-TestSuites.xml</tt> */
      public final static String DEFAULT_FILENAME = "TESTS-TestSuites.xml";
      
      
      public AggregateTransformer createReport(){
          AggregateTransformer transformer = new AggregateTransformer(this);
          transformers.add(transformer);
          return transformer;
      }
      
      /**
       * Set the name of the file aggregating the results. It must be relative
       * from the <tt>todir</tt> attribute. If not set it will use [EMAIL 
PROTECTED] DEFAULT_FILENAME}
       * @param  value   the name of the file.
       * @see #setTodir(File)
       */
      public void setTofile(String value){
          toFile = value;
      }
      
      /**
       * Set the destination directory where the results should be written. If 
not
       * set if will use [EMAIL PROTECTED] DEFAULT_DIR}. When given a relative 
directory
       * it will resolve it from the project directory.
       * @param value    the directory where to write the results, absolute or
       * relative.
       */
      public void setTodir(File value){
          toDir = value;
      }
      
      /**
       * Add a new fileset containing the xml results to aggregate
       * @param    fs      the new fileset of xml results.
       */
      public void addFileSet(FileSet fs) {
          filesets.addElement(fs);
      }
      
      /**
       * Aggregate all testsuites into a single document and write it to the
       * specified directory and file.
       * @throws        BuildException  thrown if there is a serious error 
while writing
       *                        the document.
       */
      public void execute() throws BuildException {
          Element rootElement = createDocument();
          File destFile = getDestinationFile();
          // write the document
          try {
              writeDOMTree(rootElement.getOwnerDocument(),  destFile );
          } catch (IOException e){
              throw new BuildException("Unable to write test aggregate to '" + 
destFile + "'", e);
          }
          // apply transformation
          Enumeration enum = transformers.elements();
          while (enum.hasMoreElements()) {
              AggregateTransformer transformer =
                  (AggregateTransformer) enum.nextElement();
              transformer.setXmlDocument(rootElement.getOwnerDocument());
              transformer.transform();
          }
      }
      
      /**
       * get the full destination file where to write the result. It is made of
       * the <tt>todir</tt> and <tt>tofile</tt> attributes.
       * @return the destination file where should be written the result file.
       */
      protected File getDestinationFile(){
          if (toFile == null){
              toFile = DEFAULT_FILENAME;
          }
          if (toDir == null){
              toDir = project.resolveFile(DEFAULT_DIR);
          }
          return new File(toDir, toFile);
      }
      
      /**
       * @return all files in the fileset that end with a '.xml'.
       */
      protected File[] getFiles() {
          Vector v = new Vector();
          final int size = filesets.size();
          for (int i = 0; i < size; i++) {
              FileSet fs = (FileSet) filesets.elementAt(i);
              DirectoryScanner ds = fs.getDirectoryScanner(project);
              ds.scan();
              String[] f = ds.getIncludedFiles();
              for (int j = 0; j < f.length; j++) {
                  String pathname = f[j];
                  if ( pathname.endsWith(".xml") ) {
                      File file = new File(ds.getBasedir(), pathname);
                      file = project.resolveFile(file.getPath());
                      v.addElement( file );
                  }
              }
          }
          
          File[] files = new File[v.size()];
          v.copyInto(files);
          return files;
      }
      
      //----- from now, the methods are all related to DOM tree manipulation
      
      /**
       * Write the DOM tree to a file.
       * @param doc the XML document to dump to disk.
       * @param file the filename to write the document to. Should obviouslly 
be a .xml file.
       * @throws IOException thrown if there is an error while writing the 
content.
       */
      protected void writeDOMTree(Document doc, File file) throws IOException {
          OutputStream out = new FileOutputStream( file );
          PrintWriter wri = new PrintWriter(out);
          wri.write("<?xml version=\"1.0\"?>\n");
          (new DOMElementWriter()).write(doc.getDocumentElement(), wri, 0, "  
");
          wri.flush();
          wri.close();
          // writers do not throw exceptions, so check for them.
          if (wri.checkError()){
              throw new IOException("Error while writing DOM content");
          }
      }
      
      /**
       * Create a DOM tree with firstchild as 'testsuites' and aggregates all
       * testsuite results that exists in the base directory.
       * @return        the root element of DOM tree that aggregates all 
testsuites.
       */
      protected Element createDocument() {
          // create the dom tree
          DocumentBuilder builder = getDocumentBuilder();
          Document doc = builder.newDocument();
          Element rootElement = doc.createElement(TESTSUITES);
          doc.appendChild(rootElement);
          
          // get all files and add them to the document
          File[] files = getFiles();
          for (int i = 0; i < files.length; i++) {
              try {
                  log("Parsing file: '" + files[i] + "'", Project.MSG_VERBOSE);
                  Document testsuiteDoc = builder.parse( files[i] );
                  Element elem = testsuiteDoc.getDocumentElement();
                  // make sure that this is REALLY a testsuite.
                  if ( TESTSUITE.equals(elem.getNodeName()) ) {
                      addTestSuite(rootElement, elem);
                  } else {
                      // issue a warning.
                      log("the file " + files[i] + " is not a valid testsuite 
XML document", Project.MSG_WARN);
                  }
              } catch (SAXException e){
                  // a testcase might have failed and write a zero-length 
document,
                  // It has already failed, but hey.... mm. just put a warning
                  log("The file " + files[i] + " is not a valid XML document. 
It is possibly corrupted.", Project.MSG_WARN);
              } catch (IOException e){
                  log("Error while accessing file " + files[i] + ": " + 
e.getMessage(), Project.MSG_ERR);
              }
          }
          return rootElement;
      }
      
      /**
       * Add a new testsuite node to the document, the main difference is that 
it
       * split the previous fully qualified name into a package and a name.
       * For example: <tt>org.apache.Whatever</tt> will be splitted in
       * <tt>org.apache</tt> and <tt>Whatever</tt>.
       * @param root the root element to which the <tt>testsuite</tt> node 
should
       *        be appended.
       * @param testsuite the element to append to the given root. It will 
slightly
       *        modify the original node to change the name attribute and add
       *        a package one.
       */
      protected void addTestSuite(Element root, Element testsuite){
          String fullclassname = testsuite.getAttribute(ATTR_NAME);
          int pos = fullclassname.lastIndexOf('.');
          
          // a missing . might imply no package at all. Don't get fooled.
          String pkgName = (pos == -1) ? "" : fullclassname.substring(0, pos);
          String classname = (pos == -1) ? fullclassname : 
fullclassname.substring(pos + 1);
          Element copy = (Element)DOMUtil.importNode(root, testsuite);
          
          // modify the name attribute and set the package
          copy.setAttribute(ATTR_NAME, classname);
          copy.setAttribute(ATTR_PACKAGE, pkgName);
      }
      
      /**
       * Create a new document builder. Will issue an 
<tt>ExceptionInitializerError</tt>
       * if something is going wrong. It is fatal anyway.
       * @return a new document builder to create a DOM
       * @todo factorize this somewhere else. It is duplicated code.
       */
      private static DocumentBuilder getDocumentBuilder() {
          try {
              return DocumentBuilderFactory.newInstance().newDocumentBuilder();
          } catch(Exception exc) {
              throw new ExceptionInInitializerError(exc);
          }
      }
      
  }
  
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/html/index.html
  
  Index: index.html
  ===================================================================
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 
Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd>
  
  <HTML>
        <HEAD>
        <TITLE>
                Unit Tests Results.
        </TITLE>
        </HEAD>
        <FRAMESET cols="20%,80%">
                <FRAMESET rows="30%,70%">
                        <FRAME src="all-packages.html" name="packageListFrame">
                        <FRAME src="all-classes.html" name="classListFrame">
                </FRAMESET>
                <FRAME src="overview-packages.html" name="classFrame">
        </FRAMESET>
        <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>
  </HTML>
  
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/html/stylesheet.css
  
  Index: stylesheet.css
  ===================================================================
  BODY {
        font:normal 68% verdana,arial,helvetica;
        color:#000000;
  }
  TD {
        FONT-SIZE: 68%
  }
  P {
        line-height:1.5em;
        margin-top:0.5em; margin-bottom:1.0em;
  }
  H1 {
        MARGIN: 0px 0px 5px; FONT: 165% verdana,arial,helvetica
  }
  H2 {
        MARGIN-TOP: 1em; MARGIN-BOTTOM: 0.5em; FONT: bold 125% 
verdana,arial,helvetica
  }
  H3 {
        MARGIN-BOTTOM: 0.5em; FONT: bold 115% verdana,arial,helvetica
  }
  H4 {
        MARGIN-BOTTOM: 0.5em; FONT: bold 100% verdana,arial,helvetica
  }
  H5 {
        MARGIN-BOTTOM: 0.5em; FONT: bold 100% verdana,arial,helvetica
  }
  H6 {
        MARGIN-BOTTOM: 0.5em; FONT: bold 100% verdana,arial,helvetica
  }
  .Error {
        font-weight:bold; color:red;
  }
  .Failure {
        font-weight:bold; color:purple;
  }
  
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/xsl/all-classes.xsl
  
  Index: all-classes.xsl
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <!-- This style sheet should contain just a named templates that used in the 
other specific templates -->
  <xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  
  <xsl:include href="toolkit.xsl"/>
  
  <xsl:template match="testsuites">
        <HTML>
                <HEAD>
                        <LINK REL ="stylesheet" TYPE="text/css" 
HREF="./stylesheet.css" TITLE="Style"/>
                </HEAD>
                <BODY onload="open('overview-packages.html','classFrame')">
                        <H2>Classes</H2>
                        <p>
                        <TABLE WIDTH="100%">
                                        <xsl:apply-templates select="testsuite">
                                                <xsl:sort select="@name"/>
                                        </xsl:apply-templates>
                        </TABLE>
                        </p>
                </BODY>
        </HTML>
  </xsl:template>
  
  <xsl:template match="testsuite">
        <tr>
                <td nowrap="nowrap">
                        <a target="classFrame">
                                <xsl:attribute name="href">
                                        <xsl:if test="not(@package='')">
                                                <xsl:value-of 
select="translate(@package,'.','/')"/><xsl:text>/</xsl:text>
                                        </xsl:if><xsl:value-of 
select="@name"/><xsl:text>-details.html</xsl:text>
                                </xsl:attribute>
                                <xsl:value-of select="@name"/></a>
                </td>
        </tr>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/xsl/all-packages.xsl
  
  Index: all-packages.xsl
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <!-- This style sheet should contain just a named templates that used in the 
other specific templates -->
  <xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  
  <!-- import the commun templates -->
  <xsl:include href="toolkit.xsl"/>
  
  <xsl:template match="testsuites">
        <HTML>
                <HEAD>
                        <LINK REL ="stylesheet" TYPE="text/css" 
HREF="./stylesheet.css" TITLE="Style"/>
                </HEAD>
                <BODY>
        
                        <H2><a href="all-classes.html" 
target="classListFrame">Home</a></H2>
                        <!-- create a summary on this testcase-->
                        <!--xsl:call-template 
name="SummaryTableHeadRootPackage"/-->
                        <H2>Packages</H2>
  
                        <!-- Get the list of the subpackage -->
                        <p>
                                <table width="100%">
                                        <!-- For each packages node apply the 
style describe in the below template-->
                                        <xsl:apply-templates 
select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
                                                <xsl:sort select="@package"/>
                                        </xsl:apply-templates>
                                </table>
                        </p>
                </BODY>
        </HTML>
  </xsl:template>
  
  <xsl:template match="testsuite">
        <tr>
                <td nowrap="nowrap">
                        <a 
href="{translate(@package,'.','/')}/package-summary.html" 
target="classFrame"><xsl:value-of select="@package"/></a>
                </td>
        </tr>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/xsl/class-details.xsl
  
  Index: class-details.xsl
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <!-- This style sheet should contain just a named templates that used in the 
other specific templates -->
  <xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  
  <!-- import the commun templates -->
  <xsl:include href="toolkit.xsl"/>
  
  <xsl:template match="testsuite">
        <HTML>
                <HEAD>
                        <LINK REL ="stylesheet" TYPE="text/css" TITLE="Style">
                                <xsl:attribute name="href"><xsl:call-template 
name="path"><xsl:with-param name="path" 
select="@package"/></xsl:call-template>stylesheet.css</xsl:attribute>
                        </LINK>
                </HEAD>
                <BODY>
                        <xsl:call-template name="header">
                                <xsl:with-param 
name="useFrame">yes</xsl:with-param>
                                <xsl:with-param name="path" select="@package"/>
                        </xsl:call-template>
        
                        <H2>Class <xsl:if test="not(@package = 
'')"><xsl:value-of select="@package"/>.</xsl:if><xsl:value-of 
select="@name"/></H2>
                        <p>
                        <h3>TestCase <xsl:value-of select="@name"/></h3>
                        
                        <table border="0" cellpadding="5" cellspacing="2" 
width="95%">
                                <!-- Header -->
                                <xsl:call-template name="classesSummaryHeader"/>
                                <!-- match the testcases of this package -->
                                <xsl:apply-templates select="testcase"/>
                        </table>
                        </p>
                </BODY>
        </HTML>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/xsl/classes-list.xsl
  
  Index: classes-list.xsl
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <!-- This style sheet should contain just a named templates that used in the 
other specific templates -->
  <xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  
  <!-- import the commun templates -->
  <xsl:include href="toolkit.xsl"/>
  
  <xsl:template match="testsuites">
        <HTML>
                <HEAD>
                        <LINK REL ="stylesheet" TYPE="text/css" TITLE="Style">
                                <xsl:attribute name="href"><xsl:call-template 
name="path"><xsl:with-param name="path" select="testsuite[position() = 
1]/@package"/></xsl:call-template>stylesheet.css</xsl:attribute>
                        </LINK>
                </HEAD>
                <BODY>
                        
                        <table width="100%">
                                <tr>
                                        <td nowrap="nowrap">
                                                <H2><a 
href="package-summary.html" target="classFrame"><xsl:value-of 
select="testsuite/@package"/></a></H2>
                                        </td>
                                </tr>
                        </table>
        
                        <H2>Classes</H2>
                        <p>
                        <TABLE WIDTH="100%">
                                        <xsl:apply-templates select="testsuite">
                                                <xsl:sort select="@name"/>
                                        </xsl:apply-templates>
                        </TABLE>
                        </p>
                </BODY>
        </HTML>
  </xsl:template>
  
  <xsl:template match="testsuite">
        <tr>
                <td nowrap="nowrap">
                        <a href="[EMAIL PROTECTED]" 
target="classFrame"><xsl:value-of select="@name"/></a>
                </td>
        </tr>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/xsl/overview-packages.xsl
  
  Index: overview-packages.xsl
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <!-- This style sheet should contain just a named templates that used in the 
other specific templates -->
  <xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  
  <xsl:include href="toolkit.xsl"/>
  
  <!-- Calculate all summary values -->
  <xsl:variable name="testCount" select="sum(//testsuite/@tests)"/>
  <xsl:variable name="errorCount" select="sum(//testsuite/@errors)"/>
  <xsl:variable name="failureCount" select="sum(//testsuite/@failures)"/>
  <xsl:variable name="timeCount" select="sum(//testsuite/@time)"/>
  <xsl:variable name="successRate" select="($testCount - $failureCount - 
$errorCount) div $testCount"/>
  
  <xsl:template match="testsuites">
        <HTML>
                <HEAD>
                        <LINK REL ="stylesheet" TYPE="text/css" 
HREF="stylesheet.css" TITLE="Style"/>
                </HEAD>
                <BODY>
                        <xsl:call-template name="header">
                                <xsl:with-param 
name="useFrame">yes</xsl:with-param>    
                        </xsl:call-template>
  
                        <xsl:call-template name="summary"/>
  
  
                <xsl:if test="count(testsuite[not(./@package = 
preceding-sibling::testsuite/@package)])&gt;0">  
                <h2>Packages</h2>
                <table border="0" cellpadding="5" cellspacing="2" width="95%">
                        <!--Header-->
                        <xsl:call-template name="packageSummaryHeader"/>
                        
                        <!-- write a summary for the package -->
                        <xsl:apply-templates select="testsuite[not(./@package = 
preceding-sibling::testsuite/@package) and not(./@package = '') ]" 
mode="package">
                                <xsl:sort select="@package"/>
                        </xsl:apply-templates>
                </table>
                <br/>
                </xsl:if>
  
  
                <xsl:if test="count(testsuite[./@package = ''])&gt;0">  
                <h2>Classes</h2>
                <table border="0" cellpadding="5" cellspacing="2" width="95%">
                        <!--Header-->
                        <xsl:call-template name="packageSummaryHeader"/>
                                
                        <!-- write a summary for the package -->
                        <xsl:apply-templates select="testsuite[./@package = 
'']" mode="class">
                                <xsl:sort select="@name"/>
                        </xsl:apply-templates>
                </table>
                </xsl:if>
                </BODY>
        </HTML>
  </xsl:template>
  
  <xsl:template match="testsuite" mode="package">
        <xsl:variable name="isError" select="(sum(//[EMAIL PROTECTED] = 
current()/@package]/@errors) + sum(//[EMAIL PROTECTED] = 
current()/@package]/@failures))&gt;0"/>
        <!-- write a summary for the package -->
        <tr bgcolor="#EEEEE" valign="top">
                <td><xsl:if test="$isError"><xsl:attribute 
name="class">Error</xsl:attribute></xsl:if><a 
href="{translate(@package,'.','/')}/package-summary.html"><xsl:value-of 
select="@package"/></a></td>
                <xsl:call-template name="statistics">
                        <xsl:with-param name="isError" select="$isError"/>
                </xsl:call-template>
        </tr>
  </xsl:template>
  
  <xsl:template match="testsuite" mode="class">
        <xsl:variable name="isError" select="(@errors + @failures)&gt;0"/>
        <!-- write a summary for the package -->
        <tr bgcolor="#EEEEE" valign="top">
                <td><xsl:if test="$isError"><xsl:attribute 
name="class">Error</xsl:attribute></xsl:if><a 
href="{translate(@package,'.','/')}/summary.html"><xsl:value-of 
select="@name"/></a></td>
                <xsl:call-template name="statistics">
                        <xsl:with-param name="isError" select="$isError"/>
                </xsl:call-template>
        </tr>
  </xsl:template>
  
  
  <xsl:template name="statistics">
        <xsl:variable name="isError"/>
                <td><xsl:if test="$isError"><xsl:attribute 
name="class">Error</xsl:attribute></xsl:if><xsl:value-of select="sum(//[EMAIL 
PROTECTED] = current()/@package]/@tests)"/></td>
                <td><xsl:if test="$isError"><xsl:attribute 
name="class">Error</xsl:attribute></xsl:if><xsl:value-of select="sum(//[EMAIL 
PROTECTED] = current()/@package]/@errors)"/></td>
                <td><xsl:if test="$isError"><xsl:attribute 
name="class">Error</xsl:attribute></xsl:if><xsl:value-of select="sum(//[EMAIL 
PROTECTED] = current()/@package]/@failures)"/></td>
                <td><xsl:if test="$isError"><xsl:attribute 
name="class">Error</xsl:attribute></xsl:if><xsl:value-of 
select="format-number(sum(//[EMAIL PROTECTED] = 
current()/@package]/@time),'#,###0.000')"/></td>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/xsl/overview-summary.xsl
  
  Index: overview-summary.xsl
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
version="1.0" xmlns:html="http://www.w3.org/Profiles/XHTML-transitional";>
  
  <xsl:include href="toolkit.xsl"/>
  
  <!--
        ====================================================
                Create the page structure
      ====================================================
  -->
  <xsl:template match="testsuites">
        <HTML>
                <HEAD>
                        <!--LINK REL ="stylesheet" TYPE="text/css" 
HREF="stylesheet.css" TITLE="Style"/-->
                <!-- put the style in the html so that we can mail it w/o 
problem -->
                <style type="text/css">
                        BODY {
                        font:normal 68% verdana,arial,helvetica;
                        color:#000000;
                        }
                        TD {
                        FONT-SIZE: 68%
                        }
                        P {
                        line-height:1.5em;
                        margin-top:0.5em; margin-bottom:1.0em;
                        }
                        H1 {
                        MARGIN: 0px 0px 5px; FONT: 165% verdana,arial,helvetica
                        }
                        H2 {
                        MARGIN-TOP: 1em; MARGIN-BOTTOM: 0.5em; FONT: bold 125% 
verdana,arial,helvetica
                        }
                        H3 {
                        MARGIN-BOTTOM: 0.5em; FONT: bold 115% 
verdana,arial,helvetica
                        }
                        H4 {
                        MARGIN-BOTTOM: 0.5em; FONT: bold 100% 
verdana,arial,helvetica
                        }
                        H5 {
                        MARGIN-BOTTOM: 0.5em; FONT: bold 100% 
verdana,arial,helvetica
                        }
                        H6 {
                        MARGIN-BOTTOM: 0.5em; FONT: bold 100% 
verdana,arial,helvetica
                        }
                        .Error {
                        font-weight:bold; color:red;
                        }
                        .Failure {
                        font-weight:bold; color:purple;
                        }
                        </style>                        
                </HEAD>
                <body text="#000000" bgColor="#ffffff">
                        <a name="#top"></a>
                        <xsl:call-template name="header"/>
                        
                        <!-- Summary part -->
                        <xsl:call-template name="summary"/>
                        <hr size="1" width="95%" align="left"/>
                        
                        <!-- Package List part -->
                        <xsl:call-template name="packagelist"/>
                        <hr size="1" width="95%" align="left"/>
                        
                        <!-- For each package create its part -->
                        <xsl:call-template name="packages"/>
                        <hr size="1" width="95%" align="left"/>
                        
                        <!-- For each class create the  part -->
                        <xsl:call-template name="classes"/>
                        
                </body>
        </HTML>
  </xsl:template>
        
        
        
        <!-- ================================================================== 
-->
        <!-- Write a list of all packages with an hyperlink to the anchor of    
-->
        <!-- of the package name.                                               
-->
        <!-- ================================================================== 
-->
        <xsl:template name="packagelist">       
                <h2>Packages</h2>
                Note: package statistics are not computed recursively, they 
only sum up all of its testsuites numbers.
                <table border="0" cellpadding="5" cellspacing="2" width="95%">
                        <xsl:call-template name="packageSummaryHeader"/>
                        <!-- list all packages recursively -->
                        <xsl:for-each select="./testsuite[not(./@package = 
preceding-sibling::testsuite/@package)]">
                                <xsl:sort select="@package"/>
                                <xsl:variable name="testCount" 
select="sum(../testsuite[./@package = current()/@package]/@tests)"/>
                                <xsl:variable name="errorCount" 
select="sum(../testsuite[./@package = current()/@package]/@errors)"/>
                                <xsl:variable name="failureCount" 
select="sum(../testsuite[./@package = current()/@package]/@failures)"/>
                                <xsl:variable name="timeCount" 
select="sum(../testsuite[./@package = current()/@package]/@time)"/>
                                
                                <!-- write a summary for the package -->
                                <tr bgcolor="#EEEEE" valign="top">
                                        <!-- set a nice color depending if 
there is an error/failure -->
                                        <xsl:attribute name="class">
                                                <xsl:choose>
                                                        <xsl:when 
test="$errorCount &gt; 0">Error</xsl:when>
                                                        <xsl:when 
test="$failureCount &gt; 0">Failure</xsl:when>
                                                </xsl:choose>
                                        </xsl:attribute>                        
        
                                        <td><a href="[EMAIL 
PROTECTED]"><xsl:value-of select="@package"/></a></td>
                                        <td><xsl:value-of 
select="$testCount"/></td>
                                        <td><xsl:value-of 
select="$errorCount"/></td>
                                        <td><xsl:value-of 
select="$failureCount"/></td>
                                        <td><xsl:value-of 
select="format-number($timeCount,'#,###0.000')"/></td>                          
              
                                </tr>
                        </xsl:for-each>
                </table>                
        </xsl:template>
        
        
        <!-- ================================================================== 
-->
        <!-- Write a package level report                                       
-->
        <!-- It creates a table with values from the document:                  
-->
        <!-- Name | Tests | Errors | Failures | Time                            
-->
        <!-- ================================================================== 
-->
        <xsl:template name="packages">
                <!-- create an anchor to this package name -->
                <xsl:for-each select="./testsuite[not(./@package = 
preceding-sibling::testsuite/@package)]">
                        <xsl:sort select="@package"/>
                                <a name="[EMAIL PROTECTED]"></a>
                                <h3>Package <xsl:value-of 
select="@package"/></h3>
                                
                                <table border="0" cellpadding="5" 
cellspacing="2" width="95%">
                                        <xsl:call-template 
name="packageSummaryHeader"/>
                        
                                        <!-- match the testsuites of this 
package -->
                                        <xsl:apply-templates 
select="../testsuite[./@package = current()/@package]"/>                        
           
                                </table>
                                <a href="#top">Back to top</a>
                                <p/>
                                <p/>
                </xsl:for-each>
        </xsl:template>
  
        <!-- ================================================================== 
-->
        <!-- Process a testsuite node                                           
-->
        <!-- It creates a table with values from the document:                  
-->
        <!-- Name | Tests | Errors | Failures | Time                            
-->
        <!-- It must match the table definition at the package level            
-->
        <!-- ================================================================== 
-->     
        <xsl:template match="testsuite">
                <tr bgcolor="#EEEEE" valign="top">
                        <!-- set a nice color depending if there is an 
error/failure -->
                        <xsl:attribute name="class">
                                <xsl:choose>
                                        <xsl:when test="@errors[.&gt; 
0]">Error</xsl:when>
                                        <xsl:when test="@failures[.&gt; 
0]">Failure</xsl:when>
                                </xsl:choose>
                        </xsl:attribute>
                
                        <!-- print testsuite information -->
                        <td><a href="[EMAIL PROTECTED]"><xsl:value-of 
select="@name"/></a></td>
                        <td><xsl:value-of select="@tests"/></td>
                        <td><xsl:value-of select="@errors"/></td>
                        <td><xsl:value-of select="@failures"/></td>
                        <td><xsl:value-of 
select="format-number(@time,'#,###0.000')"/></td>
                </tr>
        </xsl:template>
        
        <xsl:template name="classes">
                <xsl:for-each select="./testsuite">
                        <xsl:sort select="@name"/>
                        <!-- create an anchor to this class name -->
                        <a name="[EMAIL PROTECTED]"></a>
                        <h3>TestCase <xsl:value-of select="@name"/></h3>
                        
                        <table border="0" cellpadding="5" cellspacing="2" 
width="95%">
                                <!-- Header -->
                                <xsl:call-template name="classesSummaryHeader"/>
  
                                <!-- match the testcases of this package -->
                                <xsl:apply-templates select="testcase"/>
                        </table>
                        <a href="#top">Back to top</a>
                </xsl:for-each>
        </xsl:template>
        
  </xsl:stylesheet>
  
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/xsl/package-summary.xsl
  
  Index: package-summary.xsl
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <!-- This style sheet should contain just a named templates that used in the 
other specific templates -->
  <xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  
  <!-- import the commun templates -->
  <xsl:include href="toolkit.xsl"/>
  
  <xsl:template match="testsuites">
        <HTML>
                <HEAD>
                        <LINK REL ="stylesheet" TYPE="text/css" TITLE="Style">
                                <xsl:attribute name="href"><xsl:call-template 
name="path"><xsl:with-param name="path" select="testsuite[position() = 
1]/@package"/></xsl:call-template>stylesheet.css</xsl:attribute>
                        </LINK>
                </HEAD>
                <BODY><xsl:attribute 
name="onload">open('classes-list.html','classListFrame')</xsl:attribute>
                        <xsl:call-template name="header">
                                <xsl:with-param 
name="useFrame">yes</xsl:with-param>    
                                <xsl:with-param name="path" 
select="testsuite/@package"/>
                        </xsl:call-template>
                        <!-- create an anchor to this package name -->
                        <h3>Package <xsl:value-of 
select="testsuite/@package"/></h3>
                        
                        <table border="0" cellpadding="5" cellspacing="2" 
width="95%">
                                <!--Header-->
                                <xsl:call-template 
name="packageSummaryHeader"/>                                
                                
                                <!-- write a summary for the package -->
                                <tr bgcolor="#EEEEE" valign="top">
                                        <td><xsl:value-of 
select="testsuite/@package"/></td>
                                        <td><xsl:value-of 
select="sum(testsuite/@tests)"/></td>
                                        <td><xsl:value-of 
select="sum(testsuite/@errors)"/></td>
                                        <td><xsl:value-of 
select="sum(testsuite/@failures)"/></td>
                                        <td><xsl:value-of 
select="format-number(sum(testsuite/@time),'#,###0.000')"/></td>
                                </tr>
                        </table>
        
                        <H2>Classes</H2>
                        <p>
                        <table border="0" cellpadding="5" cellspacing="2" 
width="95%">
                                <!--Header-->
                                <xsl:call-template name="packageSummaryHeader"/>
                                
                                <!--Value-->
                                <xsl:apply-templates select="testsuite">
                                        <xsl:sort select="@name"/>
                                </xsl:apply-templates>
                        </table>
                        </p>
                </BODY>
        </HTML>
  </xsl:template>
  
  <xsl:template match="testsuite">
                <tr bgcolor="#EEEEE" valign="top">
                        <!-- set a nice color depending if there is an 
error/failure -->
                        <xsl:attribute name="class">
                                <xsl:choose>
                                        <xsl:when test="@errors[.&gt; 
0]">Error</xsl:when>
                                        <xsl:when test="@failures[.&gt; 
0]">Failure</xsl:when>
                                </xsl:choose>
                        </xsl:attribute>
                
                        <!-- print testsuite information -->
                        <td><a href="[EMAIL PROTECTED]" 
target="classFrame"><xsl:value-of select="@name"/></a></td>
                        <td><xsl:value-of select="@tests"/></td>
                        <td><xsl:value-of select="@errors"/></td>
                        <td><xsl:value-of select="@failures"/></td>
                        <td><xsl:value-of 
select="format-number(@time,'#,###0.000')"/></td>
                </tr>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  1.1                  
jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/xsl/toolkit.xsl
  
  Index: toolkit.xsl
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <!-- This style sheet should contain just a named templates that used in the 
other specific templates -->
  <xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  
  <!-- transform string like a.b.c to ../../../  -->
  <xsl:template name="path">
        <xsl:param name="path"/>
        <xsl:if test="contains($path,'.')">
                <xsl:text>../</xsl:text>        
                <xsl:call-template name="path">
                        <xsl:with-param name="path"><xsl:value-of 
select="substring-after($path,'.')"/></xsl:with-param>
                </xsl:call-template>    
        </xsl:if>
        <xsl:if test="not(contains($path,'.')) and not($path = '')">
                <xsl:text>../</xsl:text>        
        </xsl:if>       
  </xsl:template>
  
  <!--
        template that will convert a carriage return into a br tag
        @param word the text from which to convert CR to BR tag
  -->
  <xsl:template name="br-replace">
        <xsl:param name="word"/>
        <xsl:choose>
                <xsl:when test="contains($word,'&#xA;')">
                        <xsl:value-of select="substring-before($word,'&#xA;')"/>
                        <br/>
                        <xsl:call-template name="br-replace">
                                <xsl:with-param name="word" 
select="substring-after($word,'&#xA;')"/>
                        </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                        <xsl:value-of select="$word"/>
                </xsl:otherwise>
        </xsl:choose>
  </xsl:template>
  
  <!-- 
                
=====================================================================
                classes summary header
                
=====================================================================
  -->
  <xsl:template name="header">
        <xsl:param name="useFrame">no</xsl:param>
        <xsl:param name="path"/>
        <h1>Unit Tests Results</h1>
        <table width="100%">
        <tr>
                <td align="left">
                        <!--xsl:choose>
                                <xsl:when test="$useFrame='yes'">Frames&#160;
                                <a target="_top">
                                        <xsl:attribute 
name="href"><xsl:call-template name="path"><xsl:with-param name="path" 
select="$path"/></xsl:call-template>noframes.html</xsl:attribute>No 
frames</a></xsl:when>
                                <xsl:when test="$useFrame='no'"><a 
target="_top"><xsl:attribute name="href"><xsl:call-template 
name="path"><xsl:with-param name="path" 
select="$path"/></xsl:call-template>index.html</xsl:attribute>Frames</a>&#160;No
 frames</xsl:when>
                                <xsl:otherwise><code>ERROR : useFrame must have 
'no' or 'yes' as value.</code></xsl:otherwise>
                        </xsl:choose-->
                </td>
                <td align="right">Designed for use with <a 
href='http://www.junit.org'>JUnit</a> and <a 
href='http://jakarta.apache.org'>Ant</a>.</td>
        </tr>
        </table>
        <hr size="1"/>
  </xsl:template>
  
  <xsl:template name="summaryHeader">
        <tr bgcolor="#A6CAF0" valign="top">
                <td><b>Tests</b></td>
                <td><b>Failures</b></td>
                <td><b>Errors</b></td>
                <td><b>Success Rate</b></td>
                <td nowrap="nowrap"><b>Time(s)</b></td>
        </tr>
  </xsl:template>
  
  <!-- 
                
=====================================================================
                package summary header
                
=====================================================================
  -->
  <xsl:template name="packageSummaryHeader">
        <tr bgcolor="#A6CAF0" valign="top">
                <td width="75%"><b>Name</b></td>
                <td width="5%"><b>Tests</b></td>
                <td width="5%"><b>Errors</b></td>
                <td width="5%"><b>Failures</b></td>
                <td width="10%" nowrap="nowrap"><b>Time(s)</b></td>
        </tr>
  </xsl:template>
  
  <!-- 
                
=====================================================================
                classes summary header
                
=====================================================================
  -->
  <xsl:template name="classesSummaryHeader">
        <tr bgcolor="#A6CAF0" valign="top">
                <td width="18%"><b>Name</b></td>
                <td width="7%"><b>Status</b></td>
                <td width="70%"><b>Type</b></td>
                <td width="5%" nowrap="nowrap"><b>Time(s)</b></td>
        </tr>
  </xsl:template>
  
  <!-- 
                
=====================================================================
                Write the summary report
                It creates a table with computed values from the document:
                User | Date | Environment | Tests | Failures | Errors | Rate | 
Time
                Note : this template must call at the testsuites level
                
=====================================================================
  -->
        <xsl:template name="summary">
                <h2>Summary</h2>
                <xsl:variable name="testCount" 
select="sum(./testsuite/@tests)"/>
                <xsl:variable name="errorCount" 
select="sum(./testsuite/@errors)"/>
                <xsl:variable name="failureCount" 
select="sum(./testsuite/@failures)"/>
                <xsl:variable name="timeCount" select="sum(./testsuite/@time)"/>
                <xsl:variable name="successRate" select="($testCount - 
$failureCount - $errorCount) div $testCount"/>
                <table border="0" cellpadding="5" cellspacing="2" width="95%">
                <xsl:call-template name="summaryHeader"/>
                <tr bgcolor="#EEEEE" valign="top">
                        <xsl:attribute name="class">
                                <xsl:choose>
                                        <xsl:when test="./failure | 
./error">Error</xsl:when>
                                        
<xsl:otherwise>TableRowColor</xsl:otherwise>
                                </xsl:choose>
                        </xsl:attribute>                
                        <td><xsl:value-of select="$testCount"/></td>
                        <td><xsl:value-of select="$failureCount"/></td>
                        <td><xsl:value-of select="$errorCount"/></td>
                        <td><xsl:value-of 
select="format-number($successRate,'#,##0.00%')"/></td>
                        <td><xsl:value-of 
select="format-number($timeCount,'#,###0.000')"/></td>
                </tr>
                </table>
                Note: <i>failures</i> are anticipated and checked for with 
assertions while <i>errors</i> are unanticipated.
        </xsl:template>
  
  <!-- 
                
=====================================================================
                testcase report
                
=====================================================================
  -->
  <xsl:template match="testcase">
        <TR bgcolor="#EEEEE" valign="top"><xsl:attribute name="class">
                        <xsl:choose>
                                <xsl:when test="./failure | 
./error">Error</xsl:when>
                                <xsl:otherwise>TableRowColor</xsl:otherwise>
                        </xsl:choose>
                </xsl:attribute>
                <TD><xsl:value-of select="./@name"/></TD>
                <xsl:choose>
                        <xsl:when test="./failure">
                                <td>Failure</td>
                                <td><xsl:apply-templates 
select="./failure"/></td>
                        </xsl:when>
                        <xsl:when test="./error">
                                <TD>Error</TD>
                                <td><xsl:apply-templates select="./error"/></td>
                        </xsl:when>
                        <xsl:otherwise>
                                <TD>Success</TD>
                                <TD></TD>
                        </xsl:otherwise>
                </xsl:choose>
                <td><xsl:value-of 
select="format-number(@time,'#,###0.000')"/></td>
        </TR>
  </xsl:template>
  
  <!-- Note : the below template error and failure are the same style
              so just call the same style store in the toolkit template -->
  <xsl:template match="failure">
        <xsl:call-template name="display-failures"/>
  </xsl:template>
  
  <xsl:template match="error">
        <xsl:call-template name="display-failures"/>
  </xsl:template>
  
  <!-- Style for the error and failure in the tescase template -->
  <xsl:template name="display-failures">
        <xsl:choose>
                <xsl:when test="not(@message)">N/A</xsl:when>
                <xsl:otherwise>
                        <xsl:value-of select="@message"/>
                </xsl:otherwise>
        </xsl:choose>
        <!-- display the stacktrace -->
        <code>
                <p/>
                <xsl:call-template name="br-replace">
                        <xsl:with-param name="word" select="."/>
                </xsl:call-template>
        </code>
        <!-- the later is better but might be problematic for non-21" 
monitors... -->
        <!--pre><xsl:value-of select="."/></pre-->
  </xsl:template>
  
  <!-- I am sure that all nodes are called -->
  <xsl:template match="*">
        <xsl:apply-templates/>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  1.3       +26 -4     
jakarta-ant/src/main/org/apache/tools/ant/util/DOMElementWriter.java
  
  Index: DOMElementWriter.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-ant/src/main/org/apache/tools/ant/util/DOMElementWriter.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- DOMElementWriter.java     2000/12/07 15:35:55     1.2
  +++ DOMElementWriter.java     2001/02/02 17:04:01     1.3
  @@ -67,6 +67,7 @@
    *
    * @author The original author of XmlLogger
    * @author <a href="mailto:[EMAIL PROTECTED]">Stefan Bodewig</a>
  + * @author <a href="mailto:[EMAIL PROTECTED]">Stephane Bailliez</tt>
    */
   public class DOMElementWriter {
   
  @@ -119,18 +120,39 @@
           for (int i = 0; i < children.getLength(); i++) {
               Node child = children.item(i);
   
  -            if (child.getNodeType() == Node.ELEMENT_NODE) {
  +            switch (child.getNodeType()) {
  +                
  +            case Node.ELEMENT_NODE:
                   if (!hasChildren) {
                       out.write(lSep);
                       hasChildren = true;
                   }
                   write((Element)child, out, indent + 1, indentWith);
  -            }
  -
  -            if (child.getNodeType() == Node.TEXT_NODE) {
  +                break;
  +                
  +            case Node.TEXT_NODE:
  +            case Node.CDATA_SECTION_NODE:
                   out.write("<![CDATA[");
                   out.write(((Text)child).getData());
                   out.write("]]>");
  +                break;
  +
  +            case Node.ENTITY_REFERENCE_NODE:
  +                out.write('&');
  +                out.write(child.getNodeName());
  +                out.write(';');
  +                break;
  +
  +            case Node.PROCESSING_INSTRUCTION_NODE:
  +                out.write("<?");
  +                out.write(child.getNodeName());
  +                String data = child.getNodeValue();
  +                if ( data != null && data.length() > 0 ) {
  +                    out.write(' ');
  +                    out.write(data);
  +                }
  +                out.write("?>");
  +                break;
               }
           }
   
  
  
  

Reply via email to