Submitted by: Thomas Haas <thomas.haas@softwired-inc.com> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267806 13f79535-47bb-0310-9956-ffa450edef68master
@@ -80,6 +80,7 @@ | |||
<exclude name="**/WLRun.java" unless="ejb.wls.present" /> | |||
<exclude name="**/WLStop.java" unless="ejb.wls.present" /> | |||
<exclude name="**/EjbJar.java" unless="ejb.build" /> | |||
<exclude name="**/junit/*" unless="junit.present" /> | |||
</javac> | |||
<copydir src="${src.dir}" dest="${build.classes}"> | |||
@@ -266,6 +267,22 @@ | |||
<!-- Run testcase --> | |||
<!-- =================================================================== --> | |||
<target name="runtests" depends="compiletests" if="junit.present"> | |||
<!-- | |||
This would make the buildprocess fail if using an Ant version | |||
without the junit task | |||
<junit defaultprintxml="false" defaultprintsummary="true" fork="on"> | |||
<classpath> | |||
<pathelement location="${lib.dir}/${name}.jar" /> | |||
<pathelement location="${build.tests}" /> | |||
<pathelement path="${classpath}" /> | |||
<pathelement path="${java.class.path}" /> | |||
</classpath> | |||
<test name="org.apache.tools.ant.AllJUnitTests" /> | |||
</junit> | |||
--> | |||
<java fork="yes" | |||
classname="junit.textui.TestRunner" | |||
args="org.apache.tools.ant.AllJUnitTests" | |||
@@ -49,6 +49,7 @@ wlstop=org.apache.tools.ant.taskdefs.optional.ejb.WLStop | |||
vssget=org.apache.tools.ant.taskdefs.optional.vss.MSVSSGET | |||
ejbjar=org.apache.tools.ant.taskdefs.optional.ejb.EjbJar | |||
javacc=org.apache.tools.ant.taskdefs.optional.javacc.JavaCC | |||
junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask | |||
# deprecated ant tasks (kept for back compatibility) | |||
javadoc2=org.apache.tools.ant.taskdefs.Javadoc | |||
@@ -0,0 +1,75 @@ | |||
/* | |||
* 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 junit.framework.TestListener; | |||
/** | |||
* This Interface describes classes that format the results of a JUnit | |||
* testrun. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> | |||
*/ | |||
public interface JUnitResultFormatter extends TestListener { | |||
/** | |||
* The whole testsuite started. | |||
*/ | |||
public void startTestSuite(JUnitTest suite); | |||
/** | |||
* The whole testsuite ended. | |||
*/ | |||
public void endTestSuite(JUnitTest suite); | |||
} |
@@ -0,0 +1,292 @@ | |||
/* | |||
* 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.Path; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.taskdefs.*; | |||
import org.apache.tools.ant.types.Commandline; | |||
import org.apache.tools.ant.types.CommandlineJava; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.lang.reflect.InvocationTargetException; | |||
import java.lang.reflect.Method; | |||
import java.util.Enumeration; | |||
import java.util.Vector; | |||
/** | |||
* Ant task to run JUnit tests. | |||
* | |||
* <p>JUnit is a framework to create unit test. It has been initially | |||
* created by Erich Gamma and Kent Beck. JUnit can be found at <a | |||
* href="http://www.xprogramming.com/software.htm">http://www.xprogramming.com/software.htm</a>. | |||
* | |||
* <p> This ant task runs a single TestCase. By default it spans a new | |||
* Java VM to prevent interferences between different testcases, | |||
* unless <code>fork</code> has been disabled. | |||
* | |||
* @author Thomas Haas | |||
*/ | |||
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 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(String junit) { | |||
commandline.createClasspath().createPathElement().setLocation(junit); | |||
} | |||
public void setDefaulthaltonerror(boolean value) { | |||
defaults.setHaltonerror(value); | |||
} | |||
public void setDefaulthaltonfailure(boolean value) { | |||
defaults.setHaltonfailure(value); | |||
} | |||
public void setDefaultprintsummary(boolean value) { | |||
defaults.setPrintsummary(value); | |||
} | |||
public void setDefaultprintxml(boolean value) { | |||
defaults.setPrintxml(value); | |||
} | |||
public void setDefaultOutFile(boolean value) { | |||
defaultOutfile = value; | |||
} | |||
public void setTimeout(Integer value) { | |||
timeout = value; | |||
} | |||
public void setFork(boolean value) { | |||
defaults.setFork(value); | |||
} | |||
public void setJvm(String value) { | |||
defaults.setName(value); | |||
commandline.setVm(value); | |||
} | |||
public void setJvmargs(String value) { | |||
commandline.createVmArgument().setLine(value); | |||
} | |||
/** | |||
* 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(); | |||
} | |||
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; | |||
} | |||
/** | |||
* Creates a new JUnitRunner and enables fork of a new Java VM. | |||
*/ | |||
public JUnitTask() throws Exception { | |||
commandline.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner"); | |||
} | |||
/** | |||
* Runs the testcase. | |||
*/ | |||
public void execute() throws BuildException { | |||
boolean errorOccurred = false; | |||
boolean failureOccurred = false; | |||
final String oldclasspath = System.getProperty("java.class.path"); | |||
commandline.createClasspath().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 = tests.elements(); | |||
while (list.hasMoreElements()) { | |||
final 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); | |||
} | |||
int exitValue = 2; | |||
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.addLine(commandline.getCommandline()); | |||
cmdl.addLine(test.getCommandline()); | |||
execute.setCommandline(cmdl.getCommandline()); | |||
log("Execute JUnit: " + cmdl, Project.MSG_VERBOSE); | |||
exitValue = execute.execute(); | |||
} | |||
catch (IOException e) { | |||
throw new BuildException("Process fork failed.", e, | |||
location); | |||
} | |||
} else { | |||
final Object[] arg = { test }; | |||
final Class[] argType = { arg[0].getClass() }; | |||
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); | |||
} | |||
} | |||
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 | |||
if (errorOccurredHere && test.getHaltonerror() | |||
|| failureOccurredHere && test.getHaltonfailure()) { | |||
throw new BuildException("JUNIT FAILED", location); | |||
} else if (errorOccurredHere || failureOccurredHere) { | |||
log("JUNIT 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 { | |||
if (timeout == null) return null; | |||
return new ExecuteWatchdog(timeout.intValue()); | |||
} | |||
private void rename(String source, String destination) throws BuildException { | |||
final File src = new File(source); | |||
final File dest = new File(destination); | |||
if (dest.exists()) dest.delete(); | |||
src.renameTo(dest); | |||
} | |||
} |
@@ -0,0 +1,202 @@ | |||
/* | |||
* 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.Project; | |||
import org.apache.tools.ant.types.Commandline; | |||
/** | |||
* | |||
* @author Thomas Haas | |||
*/ | |||
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 boolean fork = false; | |||
private long runs, failures, errors; | |||
private long runTime; | |||
public JUnitTest() { | |||
} | |||
public JUnitTest(boolean fork, boolean haltOnError, boolean haltOnFail, | |||
boolean printSummary, boolean printXml, String name, | |||
String outfile) { | |||
this.fork = fork; | |||
this.haltOnError = haltOnError; | |||
this.haltOnFail = haltOnFail; | |||
this.printSummary = printSummary; | |||
this.printXml = printXml; | |||
this.name = name; | |||
this.outfile = outfile; | |||
} | |||
public void setFork(boolean value) { | |||
fork = value; | |||
} | |||
public boolean getFork() { | |||
return fork; | |||
} | |||
public void setHaltonerror(boolean value) { | |||
haltOnError = value; | |||
} | |||
public void setHaltonfailure(boolean value) { | |||
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) { | |||
outfile = value; | |||
} | |||
public boolean getHaltonerror() { | |||
return haltOnError; | |||
} | |||
public boolean getHaltonfailure() { | |||
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); | |||
} | |||
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(); | |||
} | |||
public void setCounts(long runs, long failures, long errors) { | |||
this.runs = runs; | |||
this.failures = failures; | |||
this.errors = errors; | |||
} | |||
public void setRunTime(long runTime) { | |||
this.runTime = runTime; | |||
} | |||
public long runCount() {return runs;} | |||
public long failureCount() {return failures;} | |||
public long errorCount() {return errors;} | |||
public long getRunTime() {return runTime;} | |||
public String toString() { | |||
return Commandline.toString(getCommandline()); | |||
} | |||
} |
@@ -0,0 +1,325 @@ | |||
/* | |||
* 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.Project; | |||
import junit.framework.*; | |||
import java.lang.reflect.*; | |||
import java.io.*; | |||
import java.util.Vector; | |||
/** | |||
* Simple Testrunner for JUnit that runs all tests of a testsuite. | |||
* | |||
* <p>This TestRunner expects a name of a TestCase class as its | |||
* argument. If this class provides a static suite() method it will be | |||
* called and the resulting Test will be run. | |||
* | |||
* <p>Otherwise all public methods starting with "test" and taking no | |||
* argument will be run. | |||
* | |||
* <p>Summary output is generated at the end. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> | |||
*/ | |||
public class JUnitTestRunner implements TestListener { | |||
/** | |||
* Holds the registered formatters. | |||
*/ | |||
private Vector formatters = new Vector(); | |||
/** | |||
* Collects TestResults. | |||
*/ | |||
private TestResult res; | |||
/** | |||
* Flag for endTest. | |||
*/ | |||
private boolean failed = true; | |||
/** | |||
* The test I'm going to run. | |||
*/ | |||
private JUnitTest junitTest; | |||
/** | |||
* The corresponding testsuite. | |||
*/ | |||
private Test suite = null; | |||
/** | |||
* Returncode | |||
*/ | |||
private int retCode = 0; | |||
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) | |||
) | |||
); | |||
} | |||
} | |||
if (junitTest.getPrintsummary()) { | |||
addFormatter(new SummaryJUnitResultFormatter()); | |||
} | |||
Class testClass = Class.forName(junitTest.getName()); | |||
try { | |||
Method suiteMethod= testClass.getMethod("suite", new Class[0]); | |||
suite = (Test)suiteMethod.invoke(null, new Class[0]); | |||
} catch(NoSuchMethodException e) { | |||
} 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(); | |||
} | |||
} | |||
public void run() { | |||
long start = System.currentTimeMillis(); | |||
if (retCode != 0) { // had an exception in the constructor | |||
return; | |||
} | |||
fireStartTestSuite(); | |||
suite.run(res); | |||
junitTest.setRunTime(System.currentTimeMillis()-start); | |||
junitTest.setCounts(res.runCount(), res.failureCount(), | |||
res.errorCount()); | |||
fireEndTestSuite(); | |||
if (res.errorCount() != 0) { | |||
retCode = 2; | |||
} else if (res.failureCount() != 0) { | |||
retCode = 1; | |||
} | |||
} | |||
/** | |||
* Returns what System.exit() would return in the standalone version. | |||
* | |||
* @return 2 if errors occurred, 1 if tests failed else 0. | |||
*/ | |||
public int getRetCode() { | |||
return retCode; | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>A new Test is started. | |||
*/ | |||
public void startTest(Test t) { | |||
failed = false; | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>A Test is finished. | |||
*/ | |||
public void endTest(Test test) { | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>A Test failed. | |||
*/ | |||
public void addFailure(Test test, Throwable t) { | |||
failed = true; | |||
if (junitTest.getHaltonfailure()) { | |||
res.stop(); | |||
} | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>An error occured while running the test. | |||
*/ | |||
public void addError(Test test, Throwable t) { | |||
failed = true; | |||
if (junitTest.getHaltonerror()) { | |||
res.stop(); | |||
} | |||
} | |||
private void fireStartTestSuite() { | |||
for (int i=0; i<formatters.size(); i++) { | |||
((JUnitResultFormatter)formatters.elementAt(i)).startTestSuite(junitTest); | |||
} | |||
} | |||
private void fireEndTestSuite() { | |||
for (int i=0; i<formatters.size(); i++) { | |||
((JUnitResultFormatter)formatters.elementAt(i)).endTestSuite(junitTest); | |||
} | |||
} | |||
public void addFormatter(JUnitResultFormatter f) { | |||
formatters.addElement(f); | |||
} | |||
/** | |||
* Entry point for standalone (forked) mode. | |||
* | |||
* Parameters: testcaseclassname plus (up to) 6 parameters in the | |||
* format key=value. | |||
* | |||
* <table cols="3" 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> | |||
* | |||
* </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); | |||
} | |||
} else { | |||
JUnitTest test = new JUnitTest(); | |||
test.setName(args[0]); | |||
args[0] = null; | |||
test.setCommandline(args); | |||
JUnitTestRunner runner = new JUnitTestRunner(test); | |||
runner.run(); | |||
if (exitAtEnd) { | |||
System.exit(runner.getRetCode()); | |||
} | |||
} | |||
} | |||
public static int runTest(JUnitTest test) { | |||
final JUnitTestRunner runner = new JUnitTestRunner(test); | |||
runner.run(); | |||
return runner.getRetCode(); | |||
} | |||
} // JUnitTestRunner |
@@ -0,0 +1,128 @@ | |||
/* | |||
* 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 java.text.NumberFormat; | |||
import junit.framework.Test; | |||
/** | |||
* Prints short summary output of the test to System.out | |||
* | |||
* @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> | |||
*/ | |||
public class SummaryJUnitResultFormatter implements JUnitResultFormatter { | |||
/** | |||
* Formatter for timings. | |||
*/ | |||
private NumberFormat nf = NumberFormat.getInstance(); | |||
public SummaryJUnitResultFormatter() { | |||
} | |||
/** | |||
* The whole testsuite started. | |||
*/ | |||
public void startTestSuite(JUnitTest suite) { | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>A new Test is started. | |||
*/ | |||
public void startTest(Test t) { | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>A Test is finished. | |||
*/ | |||
public void endTest(Test test) { | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>A Test failed. | |||
*/ | |||
public void addFailure(Test test, Throwable t) { | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>An error occured while running the test. | |||
*/ | |||
public void addError(Test test, Throwable t) { | |||
} | |||
/** | |||
* 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"); | |||
} | |||
} |
@@ -0,0 +1,235 @@ | |||
/* | |||
* 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 java.io.PrintWriter; | |||
import java.io.StringWriter; | |||
import java.text.CharacterIterator; | |||
import java.text.NumberFormat; | |||
import java.text.StringCharacterIterator; | |||
import junit.framework.Test; | |||
import junit.framework.TestCase; | |||
/** | |||
* Prints XML output of the test to a specified Writer. | |||
* | |||
* @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> | |||
*/ | |||
public class XMLJUnitResultFormatter implements JUnitResultFormatter { | |||
/** | |||
* OutputStream for XML output. | |||
*/ | |||
private PrintWriter out; | |||
/** | |||
* Collects output during the test run. | |||
*/ | |||
private StringBuffer results = new StringBuffer(); | |||
/** | |||
* platform independent line separator. | |||
*/ | |||
private static String newLine = System.getProperty("line.separator"); | |||
/** | |||
* Formatter for timings. | |||
*/ | |||
private NumberFormat nf = NumberFormat.getInstance(); | |||
/** | |||
* Timing helper. | |||
*/ | |||
private long lastTestStart = 0; | |||
public XMLJUnitResultFormatter(PrintWriter out) { | |||
this.out = out; | |||
} | |||
/** | |||
* The whole testsuite ended. | |||
*/ | |||
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(); | |||
} | |||
/** | |||
* The whole testsuite started. | |||
*/ | |||
public void startTestSuite(JUnitTest suite) { | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>A new Test is started. | |||
*/ | |||
public void startTest(Test t) { | |||
lastTestStart = System.currentTimeMillis(); | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>A Test is finished. | |||
*/ | |||
public void endTest(Test test) { | |||
formatTestCaseOpenTag(test); | |||
results.append(" </testcase>"); | |||
results.append(newLine); | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>A Test failed. | |||
*/ | |||
public void addFailure(Test test, Throwable t) { | |||
formatError("failure", test, t); | |||
} | |||
/** | |||
* Interface TestListener. | |||
* | |||
* <p>An error occured while running the test. | |||
*/ | |||
public void addError(Test test, Throwable t) { | |||
formatError("error", test, t); | |||
} | |||
/** | |||
* Translates <, & and > to corresponding entities. | |||
*/ | |||
private String xmlEscape(String orig) { | |||
if (orig == null) return ""; | |||
StringBuffer temp = new StringBuffer(); | |||
StringCharacterIterator sci = new StringCharacterIterator(orig); | |||
for (char c = sci.first(); c != CharacterIterator.DONE; | |||
c = sci.next()) { | |||
switch (c) { | |||
case '<': | |||
temp.append("<"); | |||
break; | |||
case '>': | |||
temp.append(">"); | |||
break; | |||
case '&': | |||
temp.append("&"); | |||
break; | |||
default: | |||
temp.append(c); | |||
break; | |||
} | |||
} | |||
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); | |||
} | |||
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); | |||
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); | |||
results.append(" </testcase>"); | |||
results.append(newLine); | |||
} | |||
} // XMLJUnitResultFormatter |