ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bode...@locus.apache.org
Subject cvs commit: jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit BatchTest.java FormatterElement.java PlainJUnitResultFormatter.java JUnitResultFormatter.java JUnitTask.java JUnitTest.java JUnitTestRunner.java SummaryJUnitResultFormatter.java XMLJUnitResultFormatter.java
Date Wed, 09 Aug 2000 13:12:16 GMT
bodewig     00/08/09 06:12:15

  Modified:    .        WHATSNEW build.xml
               docs     index.html
               src/main/org/apache/tools/ant/taskdefs/optional/junit
                        JUnitResultFormatter.java JUnitTask.java
                        JUnitTest.java JUnitTestRunner.java
                        SummaryJUnitResultFormatter.java
                        XMLJUnitResultFormatter.java
  Added:       docs     junit.html
               src/main/org/apache/tools/ant/taskdefs/optional/junit
                        BatchTest.java FormatterElement.java
                        PlainJUnitResultFormatter.java
  Log:
  <junit> more or less completely rewritten and documented.
  
  Revision  Changes    Path
  1.12      +2 -2      jakarta-ant/WHATSNEW
  
  Index: WHATSNEW
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/WHATSNEW,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- WHATSNEW	2000/08/07 11:47:09	1.11
  +++ WHATSNEW	2000/08/09 13:12:11	1.12
  @@ -20,9 +20,9 @@
   Other changes:
   --------------
   
  -* New tasks: sql, genkey, cab, ftp.
  +* New tasks: sql, genkey, cab, ftp, junit.
   
  -* New tasks junit, mparse, execon. All pending documentation, most of
  +* New tasks mparse, execon. All pending documentation, most of
   them pending review.
   
   * <java> uses ClassLoader of its own in no-fork mode if a classpath is
  
  
  
  1.61      +7 -6      jakarta-ant/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/build.xml,v
  retrieving revision 1.60
  retrieving revision 1.61
  diff -u -r1.60 -r1.61
  --- build.xml	2000/08/07 11:47:10	1.60
  +++ build.xml	2000/08/09 13:12:11	1.61
  @@ -295,7 +295,7 @@
       This would make the buildprocess fail if using an Ant version
       without the junit task
   
  -    <junit defaultprintxml="false" defaultprintsummary="true" fork="on">
  +    <junit printsummary="yes" fork="yes" haltonfailure="yes">
         <classpath>
           <pathelement location="${lib.dir}/${name}.jar" />
           <pathelement location="${build.tests}" />
  @@ -303,11 +303,12 @@
           <pathelement path="${java.class.path}" />
         </classpath>
   
  -      <test name="org.apache.tools.ant.IntrospectionHelperTest" />
  -      <test name="org.apache.tools.ant.types.CommandlineTest" />
  -      <test name="org.apache.tools.ant.types.CommandlineJavaTest" />
  -      <test name="org.apache.tools.ant.types.EnumeratedAttributeTest" />
  -      <test name="org.apache.tools.ant.types.PathTest" />
  +      <batchtest>
  +        <fileset dir="${src.tests.dir}">
  +          <include name="**/*Test*" />
  +          <exclude name="**/All*" />
  +        </fileset>
  +      </batchtest>
       </junit>
   -->
   
  
  
  
  1.69      +1 -0      jakarta-ant/docs/index.html
  
  Index: index.html
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/docs/index.html,v
  retrieving revision 1.68
  retrieving revision 1.69
  diff -u -r1.68 -r1.69
  --- index.html	2000/08/09 09:21:04	1.68
  +++ index.html	2000/08/09 13:12:11	1.69
  @@ -3305,6 +3305,7 @@
   <ul>
     <li><a href="#cab">Cab</a></li>
     <li><a href="#ftp">FTP</a></li>
  +  <li><a href="junit.html">JUnit</a></li>
     <li><a href="#netrexxc">NetRexxC</a></li>
     <li><a href="#renameexts">RenameExtensions</a></li>
     <li><a href="#script">Script</a></li>
  
  
  
  1.1                  jakarta-ant/docs/junit.html
  
  Index: junit.html
  ===================================================================
  <html>
  <head>
  </head>
  <body>
  
  <h2><a name="junit">JUnit</a></h2>
  <h3>Description</h3>
  
  <p>This task runs tests from the JUnit testing framework. The latest
  version of the framework can be found at <a
  href="http://www.xprogramming.com/software.htm">http://www.xprogramming.com/software.htm</a>.
  This task requires JUnit 3.0 or above.</p>
  
  <p>Tests are defined by nested <code>test</code> or
  <code>batchtest</code> tags, see <a href="#nested">nested
  elements</a>.</p>
  
  <h3>Parameters</h3>
  <table border="1" cellpadding="2" cellspacing="0">
  <tr>
    <td width="12%" valign="top"><b>Attribute</b></td>
    <td width="78%" valign="top"><b>Description</b></td>
    <td width="10%" valign="top"><b>Required</b></td>
  </tr>
    <tr>
      <td valign="top">printsummary</td> 
      <td valign="top">Print one line statistics for each testcase.</td>
      <td align="center" valign="top">No, default is "off"</td>
    </tr>
    <tr>
      <td valign="top">fork</td> 
      <td valign="top">Run the tests in a separate VM.</td>
      <td align="center" valign="top">No, default is "off"</td>
    </tr>
    <tr>
      <td valign="top">haltonerror</td> 
      <td valign="top">Stop the build process if an error occures during the test
         run.</td>
      <td align="center" valign="top">No, default is "off"</td>
    </tr>
    <tr>
      <td valign="top">haltonfailure</td> 
      <td valign="top">Stop the build process if a test fails (errors are 
        considered failures as well).</td>
      <td align="center" valign="top">No, default is "off"</td>
    </tr>
    <tr>
      <td valign="top">timeout</td> 
      <td valign="top">Cancel the individual tests if the don't finish
        in the given time (measured in milliseconds).  Ignored if fork is
        disabled.</td> 
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">maxmemory</td>
      <td valign="top">Max amount of memory to allocate to the forked VM
        (ignored if fork is disabled)</td>
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">jvm</td>
      <td valign="top">the command used to invoke the Java Virtual Machine,
        default is 'java'.  The command is resolved by java.lang.Runtime.exec().
        Ignored if fork is disabled.</td>
      <td align="center" valign="top">No, default &quot;java&quot;</td>
    </tr>
  </table>
  
  <h3><a name="nested">Nested Elements</a></h3>
  
  <p><code>junit</code> supports a nested <code>&lt;classpath&gt;</code>
  element, that represents a <a href="index.html#path">PATH like
  structure</a>. The value is ignore if <code>fork</code> is
  disabled.</p>
  
  <h4>jvmarg</h4>
  
  <p>If fork is enabled, additional parameters may be passed to the new
  VM via nested <code>&lt;jvmarg&gt;</code> attributes, for example:</p>
  
  <pre><blockquote>
  &lt;junit fork=&quot;yes&quot;&gt;
    &lt;jvmarg value=&quot;-Djava.compiler=NONE&quot;/&gt;
  &lt;/junit&gt;
  </blockquote></pre>
  would run the test in a VM without JIT.</p>
  
  <table border="1" cellpadding="2" cellspacing="0">
  <tr>
    <td width="12%" valign="top"><b>Attribute</b></td>
    <td width="78%" valign="top"><b>Description</b></td>
    <td width="10%" valign="top"><b>Required</b></td>
  </tr>
    <tr>
      <td valign="top">value</td> 
      <td valign="top">a single command line argument.</td>
      <td align="center" rowspan="4">Exactly one of these.</td>
    </tr>
    <tr>
      <td valign="top">file</td> 
      <td valign="top">The name of a file as a single command line argument.</td>
    </tr>
    <tr>
      <td valign="top">path</td> 
      <td valign="top">A string that shall be treated as a PATH
        (i.e. the PATH separator will be set according to the plattform's
        convention) as a single command line argument.</td>
    </tr>
    <tr>
      <td valign="top">line</td> 
      <td valign="top">a space delimited list of command line arguments.</td>
    </tr>
  </table>
  
  <h4>formatter</h4>
  
  <p>The results of the tests can be printed in different
  formats. Output will always be sent to a file, the name of the file is
  determined by the name of the test and can be set by the
  <code>outfile</code> attribute of <code>&lt;test&gt;</code>.
  
  <p>There are two predefined formatters, one prints the test results in
  XML format, the other emits plain text. Custom formatters that need to
  implement
  <code>org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter</code>
  can be specified.</p>
  
  <table border="1" cellpadding="2" cellspacing="0">
  <tr>
    <td width="12%" valign="top"><b>Attribute</b></td>
    <td width="78%" valign="top"><b>Description</b></td>
    <td width="10%" valign="top"><b>Required</b></td>
  </tr>
    <tr>
      <td valign="top">type</td> 
      <td valign="top">Use a predefined formatter (either "xml" or "plain").</td>
      <td align="center" rowspan="2">Exactly one of these.</td>
    </tr>
    <tr>
      <td valign="top">classname</td> 
      <td valign="top">Name of a custo formatter class.</td>
    </tr>
    <tr>
      <td valign="top">extension</td> 
      <td valign="top">Extension to append to the output filename.</td>
      <td align="center">Yes, if classname has been used.</td>
    </tr>
  </table>
  
  <h4>test</h4>
  
  <p>Defines a single test class.</p>
  
  <table border="1" cellpadding="2" cellspacing="0">
  <tr>
    <td width="12%" valign="top"><b>Attribute</b></td>
    <td width="78%" valign="top"><b>Description</b></td>
    <td width="10%" valign="top"><b>Required</b></td>
  </tr>
    <tr>
      <td valign="top">name</td> 
      <td valign="top">Name of the test class</td>
      <td align="center">Yes</td>
    </tr>
    <tr>
      <td valign="top">fork</td> 
      <td valign="top">Run the tests in a separate VM. 
        Overrides value set in <code>&lt;junit&gt;</code>.</td>
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">haltonerror</td> 
      <td valign="top">Stop the build process if an error occures during the test
         run. Overrides value set in <code>&lt;junit&gt;</code>.</td>
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">haltonfailure</td> 
      <td valign="top">Stop the build process if a test fails (errors are 
        considered failures as well).  Overrides value set in 
        <code>&lt;junit&gt;</code>.</td>
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">outfile</td> 
      <td valign="top">Basename of the test result. The full filename is
        determined by this attribute and the extension of
        <code>formatter</code>.</td>
      <td align="center" valign="top">No, default is
        <code>TEST-name</code> using the <code>name</code> attribute.</td>
    </tr>
    <tr>
      <td valign="top">if</td> 
      <td valign="top">Only run test if the named property is set.</td>
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">unless</td> 
      <td valign="top">Only run test if the named property is <b>not</b> set.</td>
      <td align="center" valign="top">No</td>
    </tr>
  </table>
  
  <p>Tests can define their own formatters via nested
  <code>&lt;formatter&gt;</code> elements.</p>
  
  <h4>batchtest</h4>
  
  <p>Define a number of tests based on pattern matching.</p>
  
  <p><code>batchtest</code> collects the included files from any number
  of nested <code>&lt;fileset&gt;</code> and
  <code>&lt;filesetref&gt;</code> elements. It then generates a test
  class name for each file that ends in <code>.java</code> or
  <code>.class</code>.</p>
  
  <table border="1" cellpadding="2" cellspacing="0">
  <tr>
    <td width="12%" valign="top"><b>Attribute</b></td>
    <td width="78%" valign="top"><b>Description</b></td>
    <td width="10%" valign="top"><b>Required</b></td>
  </tr>
    <tr>
      <td valign="top">fork</td> 
      <td valign="top">Run the tests in a separate VM. 
        Overrides value set in <code>&lt;junit&gt;</code>.</td>
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">haltonerror</td> 
      <td valign="top">Stop the build process if an error occures during the test
         run. Overrides value set in <code>&lt;junit&gt;</code>.</td>
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">haltonfailure</td> 
      <td valign="top">Stop the build process if a test fails (errors are 
        considered failures as well).  Overrides value set in 
        <code>&lt;junit&gt;</code>.</td>
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">if</td> 
      <td valign="top">Only run tests if the named property is set.</td>
      <td align="center" valign="top">No</td>
    </tr>
    <tr>
      <td valign="top">unless</td> 
      <td valign="top">Only run tests if the named property is <b>not</b> set.</td>
      <td align="center" valign="top">No</td>
    </tr>
  </table>
  
  <p>Batchtests can define their own formatters via nested
  <code>&lt;formatter&gt;</code> elements.</p>
  
  <h3>Examples</h3>
  <pre><blockquote>
  &lt;junit&gt;
    &lt;test name="my.test.TestCase" /&gt;
  &lt;/junit&gt;
  </pre></blockquote>
  
  <p>Runs the test defined in <code>my.test.TestCase</code> in the same
  VM. No output will be generated unless the test fails.</p>
  
  <pre><blockquote>
  &lt;junit printsummary="yes" fork="yes" haltonfailure="yes"&gt;
    &lt;formatter type="plain" /&gt;
    &lt;test name="my.test.TestCase" /&gt;
  &lt;/junit&gt;
  </pre></blockquote>
  
  <p>Runs the test defined in <code>my.test.TestCase</code> in a
  separate VM.  At the end of the test a single line summary will be
  printed. A detailed report of the test can be found in
  <code>TEST-my.test.TestCase.txt</code>. The build process will be
  stopped if the test fails.</p>
  
  <pre><blockquote>
  &lt;junit printsummary="yes" haltonfailure="yes"&gt;
    &lt;classpath&gt;
      &lt;pathelement location="${build.tests}" /&gt;
      &lt;pathelement path="${java.class.path}" /&gt;
    &lt;/classpath&gt;
  
    &lt;formatter type="plain" /&gt;
  
    &lt;test name="my.test.TestCase" haltonfailure="no" outfile="result" &gt;
      &lt;formatter type="xml" /&gt;
    &lt;/test&gt;
  
    &lt;batchtest fork="yes"&gt;
      &lt;fileset dir="${src.tests}"&gt;
        &lt;include name="**/*Test*.java" /&gt;
        &lt;exclude name="**/AllTests.java" /&lt;
      &lt;/fileset&gt;
    &lt;/batchtest&gt;
  &lt;/junit&gt;
  </pre></blockquote>
  
  <p>Runs <code>my.test.TestCase</code> in the same VM (ignoring the
  given CLASSPATH), only a warning is printed if this test fails. In
  addition to the plain text testresults, for this test a XML result
  will be output to <code>result.xml</code>.</p>
  
  <p>For each matching file in the directory <code>${src.tests}</code> a
  test is run in a separate VM. If a test fails, the build process is
  aborted. Results are collected in files named
  <code>TEST-<em>name</em>.txt</code>.</p>
  
  </body>
  </html>
  
  
  
  1.2       +8 -2      jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitResultFormatter.java
  
  Index: JUnitResultFormatter.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitResultFormatter.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JUnitResultFormatter.java	2000/07/20 10:02:04	1.1
  +++ JUnitResultFormatter.java	2000/08/09 13:12:12	1.2
  @@ -54,6 +54,7 @@
   
   package org.apache.tools.ant.taskdefs.optional.junit;
   
  +import org.apache.tools.ant.BuildException;
   import junit.framework.TestListener;
   
   /**
  @@ -66,10 +67,15 @@
       /**
        * The whole testsuite started.
        */
  -    public void startTestSuite(JUnitTest suite);
  +    public void startTestSuite(JUnitTest suite) throws BuildException;
   
       /**
        * The whole testsuite ended.
        */
  -    public void endTestSuite(JUnitTest suite);
  +    public void endTestSuite(JUnitTest suite) throws BuildException;
  +
  +    /**
  +     * Sets the stream the formatter is supposed to write its results to.
  +     */
  +    public void setOutput(java.io.OutputStream out);
   }
  
  
  
  1.5       +119 -122  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
  
  Index: JUnitTask.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- JUnitTask.java	2000/08/03 11:25:13	1.4
  +++ JUnitTask.java	2000/08/09 13:12:12	1.5
  @@ -82,49 +82,38 @@
    * unless <code>fork</code> has been disabled.
    *
    * @author Thomas Haas 
  + * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> 
    */
   public class JUnitTask extends Task {
   
  -    // <XXX> private final static int HALT_NOT = 1;
  -    // <XXX> private final static int HALT_IMMEDIATELY = 2;
  -    // <XXX> private final static int HALT_AT_END = 3;
  -
       private CommandlineJava commandline = new CommandlineJava();
       private Vector tests = new Vector();
  +    private Vector batchTests = new Vector();
  +    private Vector formatters = new Vector();
   
       private JUnitTest defaults = new JUnitTest();
  -    private boolean defaultOutfile = true;
       private Integer timeout = null;
  -
  -    // <XXX> private int haltOnError = HALT_AT_END;
  -    // <XXX> private int haltOnFailure = HALT_AT_END;
  -
  -    /**
  -     * Set the path to junit classes.
  -     * @param junit path to junit classes.
  -     */
  -    public void setJunit(File junit) {
  -        commandline.createClasspath(project).createPathElement().setLocation(junit);
  -    }
  +    private boolean summary = false;
   
  -    public void setDefaulthaltonerror(boolean value) {
  +    public void setHaltonerror(boolean value) {
           defaults.setHaltonerror(value);
       }
   
  -    public void setDefaulthaltonfailure(boolean value) {
  +    public void setHaltonfailure(boolean value) {
           defaults.setHaltonfailure(value);
       }
  -
  -    public void setDefaultprintsummary(boolean value) {
  -        defaults.setPrintsummary(value);
  -    }
   
  -    public void setDefaultprintxml(boolean value) {
  -        defaults.setPrintxml(value);
  +    public void setPrintsummary(boolean value) {
  +        summary = value;
       }
   
  -    public void setDefaultOutFile(boolean value) {
  -        defaultOutfile = value;
  +    public void setMaxmemory(String max) {
  +        if (Project.getJavaVersion().startsWith("1.1")) {
  +            createJvmarg().setValue("-mx"+max);
  +        } else {
  +            createJvmarg().setValue("-Xmx"+max);
  +        }
  +        
       }
   
       public void setTimeout(Integer value) {
  @@ -136,42 +125,36 @@
       }
   
       public void setJvm(String value) {
  -        defaults.setName(value);
   	commandline.setVm(value);
       }
   
  -    public void setJvmargs(String value) {
  -	commandline.createVmArgument().setLine(value);
  +    public Commandline.Argument createJvmarg() {
  +	return commandline.createVmArgument();
       }
   
  -
  -    /**
  -     * Set the classpath to be used by the testcase.
  -     * @param classpath the classpath used to run the testcase.
  -     */
  -    /*public void setClasspath(String classpath) {
  -        this.classpath = classpath;
  -    }*/
  -
  -
       public Path createClasspath() {
           return commandline.createClasspath(project);
       }
  -
  -    public JUnitTest createTest() {
  -        final JUnitTest result;
  -        result = new JUnitTest(
  -            defaults.getFork(),
  -            defaults.getHaltonerror(),
  -            defaults.getHaltonfailure(),
  -            defaults.getPrintsummary(),
  -            defaults.getPrintxml(),
  -            null, null);
   
  -        tests.addElement(result);
  -        return result;
  +    public void addTest(JUnitTest test) {
  +        test.setHaltonerror(defaults.getHaltonerror());
  +        test.setHaltonfailure(defaults.getHaltonfailure());
  +        test.setFork(defaults.getFork());
  +        tests.addElement(test);
  +    }
  +
  +    public BatchTest createBatchTest() {
  +        BatchTest test = new BatchTest(project);
  +        test.setHaltonerror(defaults.getHaltonerror());
  +        test.setHaltonfailure(defaults.getHaltonfailure());
  +        test.setFork(defaults.getFork());
  +        batchTests.addElement(test);
  +        return test;
       }
   
  +    public void addFormatter(FormatterElement fe) {
  +        formatters.addElement(fe);
  +    }
   
       /**
        * Creates a new JUnitRunner and enables fork of a new Java VM.
  @@ -186,95 +169,109 @@
       public void execute() throws BuildException {
           boolean errorOccurred = false;
           boolean failureOccurred = false;
  -
  -        final String oldclasspath = System.getProperty("java.class.path");
   
  -        commandline.createClasspath(project).createPathElement().setPath(oldclasspath);
  -        /*
  -         * This doesn't work on JDK 1.1, should use a Classloader of our own 
  -         * anyway --SB
  -         *
  -         * System.setProperty("java.class.path", commandline.createClasspath().toString());
  -         */
  +        Enumeration list = batchTests.elements();
  +        while (list.hasMoreElements()) {
  +            BatchTest test = (BatchTest)list.nextElement();
  +            Enumeration list2 = test.elements();
  +            while (list2.hasMoreElements()) {
  +                tests.addElement(list2.nextElement());
  +            }
  +        }
   
  -        Enumeration list = tests.elements();
  +        list = tests.elements();
           while (list.hasMoreElements()) {
  -            final JUnitTest test = (JUnitTest)list.nextElement();
  +            JUnitTest test = (JUnitTest)list.nextElement();
   
  -            final String filename = "TEST-" + test.getName() + ".xml";
  -// removed --SB
  -//            if (new File(filename).exists()) {
  -//                project.log("Skipping " + test.getName());
  -//                continue;
  -//            }
  -            project.log("Running " + test.getName());
  -
  -            if (defaultOutfile && (test.getOutfile() == null ||
  -                test.getOutfile().length() == 0)) {
  -
  -// removed --SB
  -//                test.setOutfile("RUNNING-" + filename);
  -                test.setOutfile(filename);
  +            if (!test.shouldRun(project)) {
  +                continue;
               }
   
  -            int exitValue = 2;
  +            if (test.getOutfile() == null) {
  +                test.setOutfile(project.resolveFile("TEST-" + test.getName()));
  +            }
   
  -            if (test.getFork()) {
  -                try {
  -		    // Create a watchdog based on the timeout attribute
  -                    final Execute execute = new Execute(new PumpStreamHandler(), createWatchdog());
  -                    final Commandline cmdl = new Commandline();
  -                    cmdl.addArguments(commandline.getCommandline());
  -                    cmdl.addArguments(test.getCommandline());
  -                    execute.setCommandline(cmdl.getCommandline());
  -                    log("Execute JUnit: " + cmdl, Project.MSG_VERBOSE);
  -                    exitValue = execute.execute();
  +            int exitValue = JUnitTestRunner.ERRORS;
  +            if (!test.getFork()) {
  +                JUnitTestRunner runner = 
  +                    new JUnitTestRunner(test, test.getHaltonerror(),
  +                                        test.getHaltonfailure());
  +                if (summary) {
  +                    log("Running " + test.getName(), Project.MSG_INFO);
  +                    
  +                    SummaryJUnitResultFormatter f = 
  +                        new SummaryJUnitResultFormatter();
  +                    f.setOutput(new LogOutputStream(this, Project.MSG_INFO));
  +                    runner.addFormatter(f);
                   }
  -                catch (IOException e) {
  -                    throw new BuildException("Process fork failed.", e, 
  -                                             location);
  +
  +                for (int i=0; i<formatters.size(); i++) {
  +                    FormatterElement fe = (FormatterElement) formatters.elementAt(i);
  +                    fe.setOutfile(project.resolveFile(test.getOutfile()
  +                                                      +fe.getExtension()));
  +                    runner.addFormatter(fe.createFormatter());
  +                }
  +                FormatterElement[] add = test.getFormatters();
  +                for (int i=0; i<add.length; i++) {
  +                    add[i].setOutfile(project.resolveFile(test.getOutfile()
  +                                                          +add[i].getExtension()));
  +                    runner.addFormatter(add[i].createFormatter());
                   }
  +
  +                runner.run();
  +                exitValue = runner.getRetCode();
  +
               } else {
  -                final Object[] arg = { test };
  -                final Class[] argType = { arg[0].getClass() };
  +                CommandlineJava cmd = (CommandlineJava) commandline.clone();
  +                
  +                cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
  +                cmd.createArgument().setValue(test.getName());
  +                cmd.createArgument().setValue("haltOnError=" 
  +                                              + test.getHaltonerror());
  +                cmd.createArgument().setValue("haltOnFailure="
  +                                              + test.getHaltonfailure());
  +                if (summary) {
  +                    log("Running " + test.getName(), Project.MSG_INFO);
  +                    
  +                    cmd.createArgument().setValue("formatter=org.apache.tools.ant.taskdefs.optional.junit.SummaryJUnitResultFormatter");
  +                }
  +
  +                for (int i=0; i<formatters.size(); i++) {
  +                    FormatterElement fe = (FormatterElement) formatters.elementAt(i);
  +                    cmd.createArgument().setValue("formatter=" +
  +                                                  fe.getClassname() + ","
  +                                                  + project.resolveFile(test.getOutfile()
  +                                                                               +fe.getExtension()).getAbsolutePath());
  +                }
  +                
  +                FormatterElement[] add = test.getFormatters();
  +                for (int i=0; i<add.length; i++) {
  +                    cmd.createArgument().setValue("formatter=" +
  +                                                  add[i].getClassname() + ","
  +                                                  + project.resolveFile(test.getOutfile()
  +                                                                               +add[i].getExtension()).getAbsolutePath());
  +                }
  +
  +                Execute execute = new Execute(new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN), createWatchdog());
  +                execute.setCommandline(cmd.getCommandline());
                   try {
  -                    final Class target = Class.forName("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
  -                    final Method main = target.getMethod("runTest", argType);
  -                    project.log("Load JUnit: " + test, Project.MSG_VERBOSE);
  -                    exitValue = ((Integer)main.invoke(null, arg)).intValue();
  -                } catch (InvocationTargetException e) {
  -                    Throwable t = e.getTargetException();
  -                    String msg = "Running test failed: " + t.getMessage();
  -                    throw new BuildException(msg, t, location);
  -                } catch (Exception e) {
  -                    String msg = "Running test failed: " + e.getMessage();
  -                    throw new BuildException(msg, e, location);
  +                    exitValue = execute.execute();
  +                } catch (IOException e) {
  +                    throw new BuildException("Process fork failed.", e, 
  +                                             location);
                   }
               }
   
  -            boolean errorOccurredHere = exitValue == 2;
  -            boolean failureOccurredHere = exitValue == 1;
  -// removed --SB
  -//            if (exitValue != 0) {
  -//                rename("RUNNING-" + filename, "ERROR-" + filename);
  -//            } else {
  -//                rename("RUNNING-" + filename, filename);
  -//            }
  -	    // <XXX> later distinguish HALT_AT_END case
  +            boolean errorOccurredHere = exitValue == JUnitTestRunner.ERRORS;
  +            boolean failureOccurredHere = exitValue != JUnitTestRunner.SUCCESS;
               if (errorOccurredHere && test.getHaltonerror()
                   || failureOccurredHere && test.getHaltonfailure()) {
  -                throw new BuildException("JUNIT FAILED", location);
  -	    } else if (errorOccurredHere || failureOccurredHere) {
  -                log("JUNIT FAILED", Project.MSG_ERR);
  +                throw new BuildException("Test "+test.getName()+" failed", 
  +                                         location);
  +            } else if (errorOccurredHere || failureOccurredHere) {
  +                log("TEST "+test.getName()+" FAILED", Project.MSG_ERR);
               }
  -
  -	    // Update overall test status
  -            errorOccurred = errorOccurred || errorOccurredHere ;
  -            failureOccurred = failureOccurred || failureOccurredHere ;
           }
  -
  -	// <XXX> later add HALT_AT_END option
  -        // Then test errorOccurred and failureOccurred here.
       }
   
       protected ExecuteWatchdog createWatchdog() throws BuildException {
  
  
  
  1.2       +44 -65    jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java
  
  Index: JUnitTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JUnitTest.java	2000/07/20 10:02:04	1.1
  +++ JUnitTest.java	2000/08/09 13:12:13	1.2
  @@ -57,36 +57,37 @@
   import org.apache.tools.ant.Project;
   import org.apache.tools.ant.types.Commandline;
   
  +import java.io.File;
  +import java.util.Vector;
  +
   /**
    *
    * @author Thomas Haas
  + * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> 
    */
   public class JUnitTest {
  -    private boolean systemExit = false;
       private boolean haltOnError = false;
       private boolean haltOnFail = false;
  -    private boolean printSummary = true;
  -    private boolean printXml = true;
       private String name = null;
  -    private String outfile = null;
  +    private File outfile = null;
       private boolean fork = false;
   
       private long runs, failures, errors;
       private long runTime;
   
  +    private Vector formatters = new Vector();
  +
       public JUnitTest() {
       }
  +
  +    public JUnitTest(String name) {
  +        this.name  = name;
  +    }
   
  -    public JUnitTest(boolean fork, boolean haltOnError, boolean haltOnFail, 
  -                     boolean printSummary, boolean printXml, String name, 
  -                     String outfile) {
  -        this.fork = fork;
  +    public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure) {
  +        this.name  = name;
           this.haltOnError = haltOnError;
           this.haltOnFail = haltOnFail;
  -        this.printSummary = printSummary;
  -        this.printXml = printXml;
  -        this.name  = name;
  -        this.outfile = outfile;
       }
   
       public void setFork(boolean value) {
  @@ -105,23 +106,14 @@
           haltOnFail = value;
       }
   
  -    public void setPrintsummary(boolean value) {
  -        printSummary = value;
  -    }
  -
  -    public void setPrintxml(boolean value) {
  -        printXml = value;
  -    }
  -
       public void setName(String value) {
           name = value;
       }
   
  -    public void setOutfile(String value) {
  +    public void setOutfile(File value) {
           outfile = value;
       }
   
  -
       public boolean getHaltonerror() {
           return haltOnError;
       }
  @@ -130,53 +122,15 @@
           return haltOnFail;
       }
   
  -    public boolean getPrintsummary() {
  -        return printSummary;
  -    }
  -
  -    public boolean getPrintxml() {
  -        return printXml;
  -    }
  -
       public String getName() {
           return name;
       }
   
       public String getOutfile() {
  -        return outfile;
  -    }
  -
  -    public void setCommandline(String [] args) {
  -        for (int i=0; i<args.length; i++) {
  -            if (args[i] == null) continue;
  -            if (args[i].startsWith("haltOnError=")) {
  -                haltOnError = Project.toBoolean(args[i].substring(12));
  -            } else if (args[i].startsWith("haltOnFailure=")) {
  -                haltOnFail = Project.toBoolean(args[i].substring(14));
  -            } else if (args[i].startsWith("printSummary=")) {
  -                printSummary = Project.toBoolean(args[i].substring(13));
  -            } else if (args[i].startsWith("printXML=")) {
  -                printXml = Project.toBoolean(args[i].substring(9));
  -            } else if (args[i].startsWith("outfile=")) {
  -                outfile = args[i].substring(8);
  -            }
  -        }
  -    }
  -
  -    public String[] getCommandline() {
  -        final Commandline result = new Commandline();
  -        if (name != null && name.length() > 0) {
  -            result.setExecutable(name);
  +        if (outfile != null) {
  +            return outfile.getAbsolutePath();
           }
  -        result.createArgument().setValue("exit=" + systemExit);
  -        result.createArgument().setValue("haltOnError=" + haltOnError);
  -        result.createArgument().setValue("haltOnFailure=" + haltOnFail);
  -        result.createArgument().setValue("printSummary=" + printSummary);
  -        result.createArgument().setValue("printXML=" + printXml);
  -        if (outfile != null && outfile.length() > 0) {
  -            result.createArgument().setValue("outfile=" + outfile);
  -        }
  -        return result.getCommandline();
  +        return null;
       }
   
       public void setCounts(long runs, long failures, long errors) {
  @@ -194,9 +148,34 @@
       public long errorCount() {return errors;}
       public long getRunTime() {return runTime;}
   
  +    private String ifProperty = null;
  +    private String unlessProperty = null;
   
  -    public String toString() {
  -        return Commandline.toString(getCommandline());
  +    public void setIf(String propertyName) {
  +        ifProperty = propertyName;
       }
   
  +    public void setUnless(String propertyName) {
  +        unlessProperty = propertyName;
  +    }
  +
  +    public boolean shouldRun(Project p) {
  +        if (ifProperty != null && p.getProperty(ifProperty) == null) {
  +            return false;
  +        } else if (unlessProperty != null && 
  +                   p.getProperty(unlessProperty) != null) {
  +            return false;
  +        }
  +        return true;
  +    }
  +
  +    public void addFormatter(FormatterElement elem) {
  +        formatters.addElement(elem);
  +    }
  +
  +    public FormatterElement[] getFormatters() {
  +        FormatterElement[] fes = new FormatterElement[formatters.size()];
  +        formatters.copyInto(fes);
  +        return fes;
  +    }
   }
  
  
  
  1.2       +112 -104  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
  
  Index: JUnitTestRunner.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JUnitTestRunner.java	2000/07/20 10:02:04	1.1
  +++ JUnitTestRunner.java	2000/08/09 13:12:13	1.2
  @@ -54,11 +54,13 @@
   
   package org.apache.tools.ant.taskdefs.optional.junit;
   
  +import org.apache.tools.ant.BuildException;
   import org.apache.tools.ant.Project;
   
   import junit.framework.*;
   import java.lang.reflect.*;
   import java.io.*;
  +import java.util.StringTokenizer;
   import java.util.Vector;
   
   /**
  @@ -79,6 +81,21 @@
   public class JUnitTestRunner implements TestListener {
   
       /**
  +     * No problems with this test.
  +     */
  +    public static final int SUCCESS = 0;
  +
  +    /**
  +     * Some tests failed.
  +     */
  +    public static final int FAILURES = 1;
  +
  +    /**
  +     * An error occured.
  +     */
  +    public static final int ERRORS = 2;
  +
  +    /**
        * Holds the registered formatters.
        */
       private Vector formatters = new Vector();
  @@ -89,14 +106,14 @@
       private TestResult res;
   
       /**
  -     * Flag for endTest.
  +     * Do we stop on errors.
        */
  -    private boolean failed = true;
  +    private boolean haltOnError = false;
   
       /**
  -     * The test I'm going to run.
  +     * Do we stop on test failures.
        */
  -    private JUnitTest junitTest;
  +    private boolean haltOnFailure = false;
   
       /**
        * The corresponding testsuite.
  @@ -104,38 +121,29 @@
       private Test suite = null;
   
       /**
  -     * Returncode
  +     * Exception caught in constructor.
        */
  -    private int retCode = 0;
  +    private Exception exception;
   
  -    public JUnitTestRunner(JUnitTest test) {
  -        junitTest = test;
  -        try {
  -            if (junitTest.getPrintxml()) {
  -                if (test.getOutfile() != null
  -                    && test.getOutfile().length() > 0) {
  -
  -                    addFormatter(new XMLJUnitResultFormatter(
  -                                     new PrintWriter(
  -                                         new FileWriter(test.getOutfile(), false)
  -                                             )
  -                                         )
  -                        );
  -                } else {
  -                    addFormatter(new XMLJUnitResultFormatter(
  -                                     new PrintWriter(
  -                                         new OutputStreamWriter(System.out), true)
  -                                         )
  -                        );
  -                }
  -            }
  +    /**
  +     * Returncode
  +     */
  +    private int retCode = SUCCESS;
   
  -            if (junitTest.getPrintsummary()) {
  -                addFormatter(new SummaryJUnitResultFormatter());
  -            }
  +    /**
  +     * The TestSuite we are currently running.
  +     */
  +    private JUnitTest junitTest;
   
  -            Class testClass = Class.forName(junitTest.getName());
  +    public JUnitTestRunner(JUnitTest test, boolean haltOnError,
  +                           boolean haltOnFailure) {
  +        this.junitTest = test;
  +        this.haltOnError = haltOnError;
  +        this.haltOnFailure = haltOnFailure;
   
  +        try {
  +            Class testClass = Class.forName(test.getName());
  +            
               try {
                   Method suiteMethod= testClass.getMethod("suite", new Class[0]);
                   suite = (Test)suiteMethod.invoke(null, new Class[0]);
  @@ -143,50 +151,48 @@
               } catch(InvocationTargetException e) {
               } catch(IllegalAccessException e) {
               }
  -
  +            
               if (suite == null) {
                   // try to extract a test suite automatically
                   // this will generate warnings if the class is no suitable Test
                   suite= new TestSuite(testClass);
               }
  -
  -            res = new TestResult();
  -            res.addListener(this);
  -            for (int i=0; i < formatters.size(); i++) {
  -                res.addListener((TestListener)formatters.elementAt(i));
  -            }
  -
  +            
           } catch(Exception e) {
  -            retCode = 2;
  -
  -            fireStartTestSuite();
  -            for (int i=0; i < formatters.size(); i++) {
  -                ((TestListener)formatters.elementAt(i)).addError(null, e);
  -            }
  -            junitTest.setCounts(1, 0, 1);
  -            junitTest.setRunTime(0);
  -            fireEndTestSuite();
  +            retCode = ERRORS;
  +            exception = e;
           }
       }
   
       public void run() {
  -        long start = System.currentTimeMillis();
  -
  -        if (retCode != 0) { // had an exception in the constructor
  -            return;
  +        res = new TestResult();
  +        res.addListener(this);
  +        for (int i=0; i < formatters.size(); i++) {
  +            res.addListener((TestListener)formatters.elementAt(i));
           }
   
  +        long start = System.currentTimeMillis();
  +
           fireStartTestSuite();
  -        suite.run(res);
  -        junitTest.setRunTime(System.currentTimeMillis()-start);
  -        junitTest.setCounts(res.runCount(), res.failureCount(),
  -                            res.errorCount());
  +        if (exception != null) { // had an exception in the constructor
  +            for (int i=0; i < formatters.size(); i++) {
  +                ((TestListener)formatters.elementAt(i)).addError(null, 
  +                                                                 exception);
  +            }
  +            junitTest.setCounts(1, 0, 1);
  +            junitTest.setRunTime(0);
  +        } else {
  +            suite.run(res);
  +            junitTest.setCounts(res.runCount(), res.failureCount(), 
  +                                res.errorCount());
  +            junitTest.setRunTime(System.currentTimeMillis() - start);
  +        }
           fireEndTestSuite();
   
  -        if (res.errorCount() != 0) {
  -            retCode = 2;
  +        if (retCode != SUCCESS || res.errorCount() != 0) {
  +            retCode = ERRORS;
           } else if (res.failureCount() != 0) {
  -            retCode = 1;
  +            retCode = FAILURES;
           }
       }
   
  @@ -204,17 +210,14 @@
        *
        * <p>A new Test is started.
        */
  -    public void startTest(Test t) {
  -        failed = false;
  -    }
  +    public void startTest(Test t) {}
   
       /**
        * Interface TestListener.
        *
        * <p>A Test is finished.
        */
  -    public void endTest(Test test) {
  -    }
  +    public void endTest(Test test) {}
   
       /**
        * Interface TestListener.
  @@ -222,9 +225,7 @@
        * <p>A Test failed.
        */
       public void addFailure(Test test, Throwable t) {
  -        failed = true;
  -
  -        if (junitTest.getHaltonfailure()) {
  +        if (haltOnFailure) {
               res.stop();
           }
       }
  @@ -235,9 +236,7 @@
        * <p>An error occured while running the test.
        */
       public void addError(Test test, Throwable t) {
  -        failed = true;
  -
  -        if (junitTest.getHaltonerror()) {
  +        if (haltOnError) {
               res.stop();
           }
       }
  @@ -261,65 +260,74 @@
       /**
        * Entry point for standalone (forked) mode.
        *
  -     * Parameters: testcaseclassname plus (up to) 6 parameters in the
  -     * format key=value.
  +     * Parameters: testcaseclassname plus parameters in the format
  +     * key=value, none of which is required.
        *
  -     * <table cols="3" border="1">
  +     * <table cols="4" border="1">
        * <tr><th>key</th><th>description</th><th>default value</th></tr>
        *
  -     * <tr><td>exit</td><td>exit with System.exit after testcase is
  -     * complete?</td><td>true</td></tr>
  -     *
        * <tr><td>haltOnError</td><td>halt test on
        * errors?</td><td>false</td></tr>
        *
        * <tr><td>haltOnFailure</td><td>halt test on
        * failures?</td><td>false</td></tr>
  -     *
  -     * <tr><td>printSummary</td><td>print summary to System.out?</td>
  -     * <td>true</td></tr>
  -     *
  -     * <tr><td>printXML</td><td>generate XML report?</td>
  -     * <td>false</td></tr>
        *
  -     * <tr><td>outfile</td><td>where to print the XML report - a
  -     * filename</td> <td>System.out</td></tr>
  +     * <tr><td>formatter</td><td>A JUnitResultFormatter given as
  +     * classname,filename. If filename is ommitted, System.out is
  +     * assumed.</td><td>none</td></tr>
        *
  -     * </table>
  +     * </table> 
        */
       public static void main(String[] args) throws IOException {
           boolean exitAtEnd = true;
           boolean haltError = false;
           boolean haltFail = false;
  -        boolean printSummary = true;
  -        boolean printXml = false;
  -        PrintWriter out = null;
   
           if (args.length == 0) {
               System.err.println("required argument TestClassName missing");
  -            if (exitAtEnd) {
  -                System.exit(2);
  +            System.exit(ERRORS);
  +        }
  +
  +        for (int i=1; i<args.length; i++) {
  +            if (args[i].startsWith("haltOnError=")) {
  +                haltError = Project.toBoolean(args[i].substring(12));
  +            } else if (args[i].startsWith("haltOnFailure=")) {
  +                haltFail = Project.toBoolean(args[i].substring(14));
  +            } else if (args[i].startsWith("formatter=")) {
  +                try {
  +                    createAndStoreFormatter(args[i].substring(10));
  +                } catch (BuildException be) {
  +                    System.err.println(be.getMessage());
  +                    System.exit(ERRORS);
  +                }
               }
  -        } else {
  +        }
  +        
  +        JUnitTest t = new JUnitTest(args[0]);
  +        JUnitTestRunner runner = new JUnitTestRunner(t, haltError, haltFail);
  +        transferFormatters(runner);
  +        runner.run();
  +        System.exit(runner.getRetCode());
  +    }
   
  -            JUnitTest test = new JUnitTest();
  -            test.setName(args[0]);
  -            args[0] = null;
  -            test.setCommandline(args);
  -            JUnitTestRunner runner = new JUnitTestRunner(test);
  -            runner.run();
  +    private static Vector fromCmdLine = new Vector();
   
  -            if (exitAtEnd) {
  -                System.exit(runner.getRetCode());
  -            }
  +    private static void transferFormatters(JUnitTestRunner runner) {
  +        for (int i=0; i<fromCmdLine.size(); i++) {
  +            runner.addFormatter((JUnitResultFormatter) fromCmdLine.elementAt(i));
           }
       }
   
  +    private static void createAndStoreFormatter(String line) 
  +        throws BuildException {
   
  -    public static int runTest(JUnitTest test) {
  -        final JUnitTestRunner runner = new JUnitTestRunner(test);
  -        runner.run();
  -        return runner.getRetCode();
  +        FormatterElement fe = new FormatterElement();
  +        StringTokenizer tok = new StringTokenizer(line, ",");
  +        fe.setClassname(tok.nextToken());
  +        if (tok.hasMoreTokens()) {
  +            fe.setOutfile(new java.io.File(tok.nextToken()));
  +        }
  +        fromCmdLine.addElement(fe.createFormatter());
       }
   
   } // JUnitTestRunner
  
  
  
  1.2       +47 -40    jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java
  
  Index: SummaryJUnitResultFormatter.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SummaryJUnitResultFormatter.java	2000/07/20 10:02:05	1.1
  +++ SummaryJUnitResultFormatter.java	2000/08/09 13:12:13	1.2
  @@ -55,10 +55,14 @@
   package org.apache.tools.ant.taskdefs.optional.junit;
   
   import java.text.NumberFormat;
  +import java.io.IOException;
  +import java.io.OutputStream;
   import junit.framework.Test;
   
  +import org.apache.tools.ant.BuildException;
  +
   /**
  - * Prints short summary output of the test to System.out
  + * Prints short summary output of the test to Ant's logging system.
    *
    * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a>
    */
  @@ -69,60 +73,63 @@
        * Formatter for timings.
        */
       private NumberFormat nf = NumberFormat.getInstance();
  -
  -    public SummaryJUnitResultFormatter() {
  -    }
  -
       /**
  -     * The whole testsuite started.
  +     * OutputStream to write to.
        */
  -    public void startTestSuite(JUnitTest suite) {
  -    }
  +    private OutputStream out;
   
       /**
  -     * Interface TestListener.
  -     *
  -     * <p>A new Test is started.
  +     * Empty
        */
  -    public void startTest(Test t) {
  -    }
  -
  +    public SummaryJUnitResultFormatter() {}
       /**
  -     * Interface TestListener.
  -     *
  -     * <p>A Test is finished.
  +     * Empty
        */
  -    public void endTest(Test test) {
  -    }
  -
  +    public void startTestSuite(JUnitTest suite) {}
       /**
  -     * Interface TestListener.
  -     *
  -     * <p>A Test failed.
  +     * Empty
        */
  -    public void addFailure(Test test, Throwable t) {
  -    }
  -
  +    public void startTest(Test t) {}
  +    /**
  +     * Empty
  +     */
  +    public void endTest(Test test) {}
  +    /**
  +     * Empty
  +     */
  +    public void addFailure(Test test, Throwable t) {}
       /**
  -     * Interface TestListener.
  -     *
  -     * <p>An error occured while running the test.
  +     * Empty
        */
  -    public void addError(Test test, Throwable t) {
  +    public void addError(Test test, Throwable t) {}
  +    
  +    public void setOutput(OutputStream out) {
  +        this.out = out;
       }
   
       /**
        * The whole testsuite ended.
        */
  -    public void endTestSuite(JUnitTest suite) {
  -        System.out.print("Tests run: ");
  -        System.out.print(suite.runCount());
  -        System.out.print(", Failures: ");
  -        System.out.print(suite.failureCount());
  -        System.out.print(", Errors: ");
  -        System.out.print(suite.errorCount());
  -        System.out.print(", Time ellapsed: ");
  -        System.out.print(nf.format(suite.getRunTime()/1000.0));
  -        System.out.println(" sec");
  +    public void endTestSuite(JUnitTest suite) throws BuildException {
  +        StringBuffer sb = new StringBuffer("Tests run: ");
  +        sb.append(suite.runCount());
  +        sb.append(", Failures: ");
  +        sb.append(suite.failureCount());
  +        sb.append(", Errors: ");
  +        sb.append(suite.errorCount());
  +        sb.append(", Time elapsed: ");
  +        sb.append(nf.format(suite.getRunTime()/1000.0));
  +        sb.append(" sec");
  +        sb.append(System.getProperty("line.separator"));
  +        try {
  +            out.write(sb.toString().getBytes());
  +            out.flush();
  +        } catch (IOException ioex) {
  +            throw new BuildException("Unable to write summary output", ioex);
  +        } finally {
  +            try {
  +                out.close();
  +            } catch (IOException e) {}
  +        }
       }
   }
  
  
  
  1.2       +151 -74   jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java
  
  Index: XMLJUnitResultFormatter.java
  ===================================================================
  RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- XMLJUnitResultFormatter.java	2000/07/20 10:02:05	1.1
  +++ XMLJUnitResultFormatter.java	2000/08/09 13:12:13	1.2
  @@ -54,11 +54,15 @@
   
   package org.apache.tools.ant.taskdefs.optional.junit;
   
  -import java.io.PrintWriter;
  -import java.io.StringWriter;
  -import java.text.CharacterIterator;
  +import java.io.*;
   import java.text.NumberFormat;
  +import java.text.CharacterIterator;
   import java.text.StringCharacterIterator;
  +import java.util.*;
  +import javax.xml.parsers.*;
  +import org.w3c.dom.*;
  +import org.apache.tools.ant.BuildException;
  +
   import junit.framework.Test;
   import junit.framework.TestCase;
   
  @@ -70,57 +74,81 @@
   
   public class XMLJUnitResultFormatter implements JUnitResultFormatter {
   
  +    private static DocumentBuilder getDocumentBuilder() {
  +        try {
  +            return DocumentBuilderFactory.newInstance().newDocumentBuilder();
  +        }
  +        catch(Exception exc) {
  +            throw new ExceptionInInitializerError(exc);
  +        }
  +    }
  +
       /**
  -     * OutputStream for XML output.
  +     * Formatter for timings.
        */
  -    private PrintWriter out;
  +    private NumberFormat nf = NumberFormat.getInstance();
       /**
  -     * Collects output during the test run.
  +     * The XML document.
        */
  -    private StringBuffer results = new StringBuffer();
  +    private Document doc;
       /**
  -     * platform independent line separator.
  +     * The wrapper for the whole testsuite.
        */
  -    private static String newLine = System.getProperty("line.separator");
  +    private Element rootElement;
       /**
  -     * Formatter for timings.
  +     * Element for the current test.
        */
  -    private NumberFormat nf = NumberFormat.getInstance();
  +    private Element currentTest;
       /**
        * Timing helper.
        */
       private long lastTestStart = 0;
  +    /**
  +     * Where to write the log to.
  +     */
  +    private OutputStream out;
   
  -    public XMLJUnitResultFormatter(PrintWriter out) {
  +    public XMLJUnitResultFormatter() {}
  +
  +    public void setOutput(OutputStream out) {
           this.out = out;
       }
   
       /**
  -     * The whole testsuite ended.
  +     * The whole testsuite started.
        */
  -    public void endTestSuite(JUnitTest suite) {
  -        out.println("<?xml version=\"1.0\"?>");
  -        out.print("<testsuite name=\"");
  -        out.print(suite.getName());
  -        out.print("\" tests=\"");
  -        out.print(suite.runCount());
  -        out.print("\" failures=\"");
  -        out.print(suite.failureCount());
  -        out.print("\" errors=\"");
  -        out.print(suite.errorCount());
  -        out.print("\" time=\"");
  -        out.print(nf.format(suite.getRunTime()/1000.0));
  -        out.println(" sec\">");
  -        out.print(results.toString());
  -        out.println("</testsuite>");
  -        out.flush();
  -        out.close();
  +    public void startTestSuite(JUnitTest suite) {
  +        doc = getDocumentBuilder().newDocument();
  +        rootElement = doc.createElement("testsuite");
  +        rootElement.setAttribute("name", xmlEscape(suite.getName()));
       }
   
       /**
  -     * The whole testsuite started.
  +     * The whole testsuite ended.
        */
  -    public void startTestSuite(JUnitTest suite) {
  +    public void endTestSuite(JUnitTest suite) throws BuildException {
  +        rootElement.setAttribute("tests", ""+suite.runCount());
  +        rootElement.setAttribute("failures", ""+suite.failureCount());
  +        rootElement.setAttribute("errors", ""+suite.errorCount());
  +        rootElement.setAttribute("time", 
  +                                 nf.format(suite.getRunTime()/1000.0)+" sec");
  +        if (out != null) {
  +            Writer wri = null;
  +            try {
  +                wri = new OutputStreamWriter(out);
  +                wri.write("<?xml version=\"1.0\"?>\n");
  +                write(rootElement, wri, 0);
  +                wri.flush();
  +            } catch(IOException exc) {
  +                throw new BuildException("Unable to write log file", exc);
  +            } finally {
  +                if (wri != null) {
  +                    try {
  +                        wri.close();
  +                    } catch (IOException e) {}
  +                }
  +            }
  +        }
       }
   
       /**
  @@ -130,6 +158,9 @@
        */
       public void startTest(Test t) {
           lastTestStart = System.currentTimeMillis();
  +        currentTest = doc.createElement("testcase");
  +        currentTest.setAttribute("name", xmlEscape(((TestCase) t).name()));
  +        rootElement.appendChild(currentTest);
       }
   
       /**
  @@ -138,9 +169,9 @@
        * <p>A Test is finished.
        */
       public void endTest(Test test) {
  -        formatTestCaseOpenTag(test);
  -        results.append("  </testcase>");
  -        results.append(newLine);
  +        currentTest.setAttribute("time", 
  +                                 nf.format((System.currentTimeMillis()-lastTestStart)
  +                                           / 1000.0));
       }
   
       /**
  @@ -161,8 +192,33 @@
           formatError("error", test, t);
       }
   
  +    private void formatError(String type, Test test, Throwable t) {
  +        if (test != null) {
  +            endTest(test);
  +        }
  +
  +        Element nested = doc.createElement(type);
  +        if (test != null) {
  +            currentTest.appendChild(nested);
  +        } else {
  +            rootElement.appendChild(nested);
  +        }
  +
  +        String message = t.getMessage();
  +        if (message != null && message.length() > 0) {
  +            nested.setAttribute("message", xmlEscape(t.getMessage()));
  +        }
  +        nested.setAttribute("type", xmlEscape(t.getClass().getName()));
  +
  +        StringWriter swr = new StringWriter();
  +        t.printStackTrace(new PrintWriter(swr, true));
  +        Text trace = doc.createTextNode(swr.toString());
  +        nested.appendChild(trace);
  +    }
  +
  +
       /**
  -     * Translates <, & and > to corresponding entities.
  +     * Translates <, & , " and > to corresponding entities.
        */
       private String xmlEscape(String orig) {
           if (orig == null) return "";
  @@ -178,6 +234,9 @@
               case '>':
                   temp.append("&gt;");
                   break;
  +            case '\"':
  +                temp.append("&quot;");
  +                break;
               case '&':
                   temp.append("&amp;");
                   break;
  @@ -189,47 +248,65 @@
           return temp.toString();
       }
   
  -    private void formatTestCaseOpenTag(Test test) {
  -        results.append("  <testcase");
  -        if (test != null && test instanceof TestCase) {
  -            results.append(" name=\"");
  -            results.append(((TestCase) test).name());
  -            results.append("\"");
  -        }
  -        results.append(" time=\"");
  -        results.append(nf.format((System.currentTimeMillis()-lastTestStart)
  -                                 / 1000.0));
  -        results.append("\">");
  -        results.append(newLine);
  -    }
  +    /**
  +     *  Writes a DOM element to a stream.
  +     */
  +    private static void write(Element element, Writer out, int indent) throws IOException {
  +        // Write indent characters
  +        for (int i = 0; i < indent; i++) {
  +            out.write("\t");
  +        }
   
  -    private void formatError(String type, Test test, Throwable t) {
  -        formatTestCaseOpenTag(test);
  -        results.append("    <");
  -        results.append(type);
  -        results.append(" message=\"");
  -        results.append(xmlEscape(t.getMessage()));
  -        results.append("\" type=\"");
  -        results.append(t.getClass().getName());
  -        results.append("\">");
  -        results.append(newLine);
  +        // Write element
  +        out.write("<");
  +        out.write(element.getTagName());
  +
  +        // Write attributes
  +        NamedNodeMap attrs = element.getAttributes();
  +        for (int i = 0; i < attrs.getLength(); i++) {
  +            Attr attr = (Attr) attrs.item(i);
  +            out.write(" ");
  +            out.write(attr.getName());
  +            out.write("=\"");
  +            out.write(attr.getValue());
  +            out.write("\"");
  +        }
  +        out.write(">");
   
  -        results.append("<![CDATA[");
  -        results.append(newLine);
  -        StringWriter swr = new StringWriter();
  -        t.printStackTrace(new PrintWriter(swr, true));
  -        results.append(swr.toString());
  -        results.append("]]>");
  -        results.append(newLine);
  -
  -        results.append("    </");
  -        results.append(type);
  -        results.append(">");
  -        results.append(newLine);
  +        // Write child attributes and text
  +        boolean hasChildren = false;
  +        NodeList children = element.getChildNodes();
  +        for (int i = 0; i < children.getLength(); i++) {
  +            Node child = children.item(i);
  +
  +            if (child.getNodeType() == Node.ELEMENT_NODE) {
  +                if (!hasChildren) {
  +                    out.write("\n");
  +                    hasChildren = true;
  +                }
  +                write((Element)child, out, indent + 1);
  +            }
   
  -        results.append("  </testcase>");
  -        results.append(newLine);
  -    }
  +            if (child.getNodeType() == Node.TEXT_NODE) {
  +                out.write("<![CDATA[");
  +                out.write(((Text)child).getData());
  +                out.write("]]>");
  +            }
  +        }
  +
  +        // If we had child elements, we need to indent before we close
  +        // the element, otherwise we're on the same line and don't need
  +        // to indent
  +        if (hasChildren) {
  +            for (int i = 0; i < indent; i++) {
  +                out.write("\t");
  +            }
  +        }
   
  +        // Write element close
  +        out.write("</");
  +        out.write(element.getTagName());
  +        out.write(">\n");
  +    }
   
   } // XMLJUnitResultFormatter
  
  
  
  1.1                  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java
  
  Index: BatchTest.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", "Tomcat", 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 apache@apache.org.
   *
   * 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.BuildException;
  import org.apache.tools.ant.DirectoryScanner;
  import org.apache.tools.ant.Project;
  import org.apache.tools.ant.types.FileSet;
  import org.apache.tools.ant.types.Reference;
  
  import java.util.*;
  
  /**
   * Create JUnitTests from a list of files.
   *
   * @author <a href="mailto:jeff.martin@synamic.co.uk">Jeff Martin</a>
   * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> 
   */
  public final class BatchTest {
      private boolean fork=false;
      private boolean haltOnError=false;
      private boolean haltOnFailure=false;
      private Project project;
      private String ifCond = null;
      private String unlessCond = null;
  
      private Vector filesets = new Vector();
      private Vector formatters = new Vector();
  
      public BatchTest(Project project){
          this.project = project;
      }
  
      public void addFileSet(FileSet fs) {
          filesets.addElement(fs);
      }
  
      public void addFileSetRef(Reference r) {
          filesets.addElement(r);
      }
  
      public void addFormatter(FormatterElement elem) {
          formatters.addElement(elem);
      }
  
      public void setIf(String propertyName) {
          ifCond = propertyName;
      }
  
      public void setUnless(String propertyName) {
          unlessCond = propertyName;
      }
  
      public final void setFork(boolean value) {
          this.fork = value;
      }
      public final void setHaltonerror(boolean value) {
          this.haltOnError = value;
      }
      public final void setHaltonfailure(boolean value) {
          this.haltOnFailure = value;
      }
      public final Enumeration elements(){
          return new FileList();
      }
      public class FileList implements Enumeration{
          private String files[]=null;
          private int i=0;
          
          private FileList(){
              Vector v = new Vector();
              for (int j=0; j<filesets.size(); j++) {
                  Object o = filesets.elementAt(j);
                  FileSet fs = null;
                  if (o instanceof FileSet) {
                      fs = (FileSet) o;
                  } else {
                      Reference r = (Reference) o;
                      o = r.getReferencedObject(project);
                      if (o instanceof FileSet) {
                          fs = (FileSet) o;
                      } else {
                          String msg = r.getRefId()+" doesn\'t denote a fileset";
                          throw new BuildException(msg);
                      }
                  }
                  DirectoryScanner ds = fs.getDirectoryScanner(project);
                  ds.scan();
                  String[] f = ds.getIncludedFiles();
                  for (int k=0; k<f.length; k++) {
                      if (f[k].endsWith(".java")) {
                          v.addElement(f[k].substring(0, f[k].length()-5));
                      } else if (f[k].endsWith(".class")) {
                          v.addElement(f[k].substring(0, f[k].length()-6));
                      }
                  }
              }
  
              files = new String[v.size()];
              v.copyInto(files);
          }
          public final boolean hasMoreElements(){
              if(i<files.length)return true;
              return false;
          }
          public final Object nextElement() throws NoSuchElementException{
              if(hasMoreElements()){
                  JUnitTest test = new JUnitTest(javaToClass(files[i]));
                  test.setHaltonerror(haltOnError);
                  test.setHaltonfailure(haltOnFailure);
                  test.setFork(fork);
                  test.setIf(ifCond);
                  test.setUnless(unlessCond);
                  Enumeration list = formatters.elements();
                  while (list.hasMoreElements()) {
                      test.addFormatter((FormatterElement)list.nextElement());
                  }
                  i++;
                  return test;
              }
              throw new NoSuchElementException();
          }
          public final String javaToClass(String fileName){
              return fileName.replace(java.io.File.separatorChar, '.');
          }
      }
  }
  
  
  
  1.1                  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/FormatterElement.java
  
  Index: FormatterElement.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", "Tomcat", 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 apache@apache.org.
   *
   * 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.BuildException;
  import org.apache.tools.ant.types.EnumeratedAttribute;
  
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.OutputStream;
  
  /**
   * Serves as a wrapper the implementations of JUnitResultFormatter,
   * for example as a nested <formatter> element in <junit>.
   *
   * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> 
   */
  public class FormatterElement {
  
      private String classname;
      private String extension;
      private OutputStream out = System.out;
      private File outFile;
  
      public void setType(TypeAttribute type) {
          if ("xml".equals(type.getValue())) {
              setClassname("org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter");
              setExtension(".xml");
          } else { // must be plain, ensured by TypeAttribute
              setClassname("org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter");
              setExtension(".txt");
          }
      }
  
      public void setClassname(String classname) {
          this.classname = classname;
      }
  
      public String getClassname() {
          return classname;
      }
  
      public void setExtension(String ext) {
          this.extension = ext;
      }
  
      public String getExtension() {
          return extension;
      }
  
      void setOutfile(File out) {
          this.outFile = out;
      }
  
      public void setOutput(OutputStream out) {
          this.out = out;
      }
  
      JUnitResultFormatter createFormatter() throws BuildException {
          if (classname == null) {
              throw new BuildException("you must specify type or classname");
          }
          
          Class f = null;
          try {
              f = Class.forName(classname);
          } catch (ClassNotFoundException e) {
              throw new BuildException(e);
          }
  
          Object o = null;
          try {
              o = f.newInstance();
          } catch (InstantiationException e) {
              throw new BuildException(e);
          } catch (IllegalAccessException e) {
              throw new BuildException(e);
          }
  
          if (!(o instanceof JUnitResultFormatter)) {
              throw new BuildException(classname+" is not a JUnitResultFormatter");
          }
  
          JUnitResultFormatter r = (JUnitResultFormatter) o;
  
          if (outFile != null) {
              try {
                  out = new FileOutputStream(outFile);
              } catch (java.io.IOException e) {
                  throw new BuildException(e);
              }
          }
          r.setOutput(out);
          return r;
      }
  
      /**
       * Enumerated attribute with the values "plain" and "xml".
       */
      public static class TypeAttribute extends EnumeratedAttribute {
          public String[] getValues() {
              return new String[] {"plain", "xml"};
          }
      }
  }
  
  
  
  1.1                  jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java
  
  Index: PlainJUnitResultFormatter.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", "Tomcat", 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 apache@apache.org.
   *
   * 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.BuildException;
  
  import java.io.*;
  import java.text.NumberFormat;
  
  import junit.framework.Test;
  import junit.framework.TestCase;
  
  /**
   * Prints plain text output of the test to a specified Writer.
   *
   * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a>
   */
  
  public class PlainJUnitResultFormatter implements JUnitResultFormatter {
  
      /**
       * Formatter for timings.
       */
      private NumberFormat nf = NumberFormat.getInstance();
      /**
       * Timing helper.
       */
      private long lastTestStart = 0;
      /**
       * Where to write the log to.
       */
      private OutputStream out;
      /**
       * Helper to store intermediate output.
       */
      private StringWriter inner;
      /**
       * Convenience layer on top of {@link #inner inner}.
       */
      private PrintWriter wri;
      /**
       * Suppress endTest if testcase failed.
       */
      private boolean failed = true;
  
      public PlainJUnitResultFormatter() {
          inner = new StringWriter();
          wri = new PrintWriter(inner);
      }
  
      public void setOutput(OutputStream out) {
          this.out = out;
      }
  
      /**
       * Empty.
       */
      public void startTestSuite(JUnitTest suite) {
      }
  
      /**
       * The whole testsuite ended.
       */
      public void endTestSuite(JUnitTest suite) throws BuildException {
          StringBuffer sb = new StringBuffer("Testsuite: ");
          sb.append(suite.getName());
          sb.append(System.getProperty("line.separator"));
          sb.append("Tests run: ");
          sb.append(suite.runCount());
          sb.append(", Failures: ");
          sb.append(suite.failureCount());
          sb.append(", Errors: ");
          sb.append(suite.errorCount());
          sb.append(", Time elapsed: ");
          sb.append(nf.format(suite.getRunTime()/1000.0));
          sb.append(" sec");
          sb.append(System.getProperty("line.separator"));
          sb.append(System.getProperty("line.separator"));
  
          if (out != null) {
              try {
                  out.write(sb.toString().getBytes());
                  wri.close();
                  out.write(inner.toString().getBytes());
                  out.flush();
              } catch (IOException ioex) {
                  throw new BuildException("Unable to write output", ioex);
              } finally {
                  try {
                      out.close();
                  } catch (IOException e) {}
              }
          }
      }
  
      /**
       * Interface TestListener.
       *
       * <p>A new Test is started.
       */
      public void startTest(Test t) {
          lastTestStart = System.currentTimeMillis();
          wri.print("Testcase: " + ((TestCase) t).name());
          failed = false;
      }
  
      /**
       * Interface TestListener.
       *
       * <p>A Test is finished.
       */
      public void endTest(Test test) {
          if (failed) return;
          wri.println(" took " 
                      + nf.format((System.currentTimeMillis()-lastTestStart)
                                  / 1000.0)
                      + " sec");
      }
  
      /**
       * Interface TestListener.
       *
       * <p>A Test failed.
       */
      public void addFailure(Test test, Throwable t) {
          formatError("\tFAILED", test, t);
      }
  
      /**
       * Interface TestListener.
       *
       * <p>An error occured while running the test.
       */
      public void addError(Test test, Throwable t) {
          formatError("\tCaused an ERROR", test, t);
      }
  
      private void formatError(String type, Test test, Throwable t) {
          if (test != null) {
              endTest(test);
          }
          failed = true;
  
          wri.println(type);
          wri.println(t.getMessage());
          t.printStackTrace(wri);
          wri.println("");
      }
  } // PlainJUnitResultFormatter
  
  
  

Mime
View raw message