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 "java"</td>
</tr>
</table>
<h3><a name="nested">Nested Elements</a></h3>
<p><code>junit</code> supports a nested <code><classpath></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><jvmarg></code> attributes, for example:</p>
<pre><blockquote>
<junit fork="yes">
<jvmarg value="-Djava.compiler=NONE"/>
</junit>
</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><test></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><junit></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><junit></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><junit></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><formatter></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><fileset></code> and
<code><filesetref></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><junit></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><junit></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><junit></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><formatter></code> elements.</p>
<h3>Examples</h3>
<pre><blockquote>
<junit>
<test name="my.test.TestCase" />
</junit>
</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>
<junit printsummary="yes" fork="yes" haltonfailure="yes">
<formatter type="plain" />
<test name="my.test.TestCase" />
</junit>
</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>
<junit printsummary="yes" haltonfailure="yes">
<classpath>
<pathelement location="${build.tests}" />
<pathelement path="${java.class.path}" />
</classpath>
<formatter type="plain" />
<test name="my.test.TestCase" haltonfailure="no" outfile="result" >
<formatter type="xml" />
</test>
<batchtest fork="yes">
<fileset dir="${src.tests}">
<include name="**/*Test*.java" />
<exclude name="**/AllTests.java" /<
</fileset>
</batchtest>
</junit>
</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:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]">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(">");
break;
+ case '\"':
+ temp.append(""");
+ break;
case '&':
temp.append("&");
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 [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.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:[EMAIL PROTECTED]">Jeff Martin</a>
* @author <a href="mailto:[EMAIL PROTECTED]">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 [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.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:[EMAIL PROTECTED]">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 [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.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:[EMAIL PROTECTED]">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 [EMAIL PROTECTED] #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