There is no automatic testcase for this, but if your run ant -f src/etc/testcases/taskdefs/optional/junit.xml -Dshowoutput=off ant -f src/etc/testcases/taskdefs/optional/junit.xml -Dshowoutput=on you'll see it in action. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272496 13f79535-47bb-0310-9956-ffa450edef68master
@@ -4,10 +4,6 @@ Changes from Ant 1.4.1 to current CVS version | |||||
Changes that could break older environments: | Changes that could break older environments: | ||||
-------------------------------------------- | -------------------------------------------- | ||||
* Shipped XML parser is now Xerces 2.0.1 along with the XML Parser APIs. | |||||
XML Parser APIs is a separate jar that contains the necessary | |||||
JAXP/DOM/SAX classes. | |||||
* Important: Single $ signs are no longer silently stripped! | * Important: Single $ signs are no longer silently stripped! | ||||
Before you panic that we have broken all your build files, we have kept | Before you panic that we have broken all your build files, we have kept | ||||
the old "$$" -> "$" behaviour. So only build files which accidentally had | the old "$$" -> "$" behaviour. So only build files which accidentally had | ||||
@@ -16,6 +12,10 @@ Changes that could break older environments: | |||||
build file which works on ant versions 1.4.1 or earlier, stay with | build file which works on ant versions 1.4.1 or earlier, stay with | ||||
the double $$ sign rule. | the double $$ sign rule. | ||||
* Shipped XML parser is now Xerces 2.0.1 along with the XML Parser APIs. | |||||
XML Parser APIs is a separate jar that contains the necessary | |||||
JAXP/DOM/SAX classes. | |||||
* <telnet> was fixed to expand properties inside nested <read> and | * <telnet> was fixed to expand properties inside nested <read> and | ||||
<write> elements; before this only happened when you assigned the text | <write> elements; before this only happened when you assigned the text | ||||
to the string attribute. If you had $ signs in the string, they may | to the string attribute. If you had $ signs in the string, they may | ||||
@@ -321,6 +321,11 @@ Other changes: | |||||
* org.apache.tools.ant.XmlLogger now is a BuildLogger, rather than just | * org.apache.tools.ant.XmlLogger now is a BuildLogger, rather than just | ||||
a BuildListener. It can operate in either mode successfully. | a BuildListener. It can operate in either mode successfully. | ||||
* <junit> has a new attribute "showoutput". If set to true, output | |||||
generated by tests will be sent to Ant's logging system as well as | |||||
to the formatters (instead of sending it to the formatters | |||||
exclusively). | |||||
Changes from Ant 1.4 to Ant 1.4.1 | Changes from Ant 1.4 to Ant 1.4.1 | ||||
=========================================== | =========================================== | ||||
@@ -340,27 +340,6 @@ | |||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | <font color="#000000" size="-1" face="arial,helvetica,sanserif"> | ||||
Stefan, others welcome | Stefan, others welcome | ||||
</font> | </font> | ||||
</td> | |||||
</tr> | |||||
<tr> | |||||
<td bgcolor="#a0ddf0" colspan="" rowspan="" | |||||
valign="top" align="left"> | |||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | |||||
JUnit's System.err/.out handling | |||||
</font> | |||||
</td> | |||||
<td bgcolor="#a0ddf0" colspan="" rowspan="" | |||||
valign="top" align="left"> | |||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | |||||
Currently this is coupled to SummaryResultFormatter - | |||||
no SummaryFormatter, no output. Want to decouple it. | |||||
</font> | |||||
</td> | |||||
<td bgcolor="#a0ddf0" colspan="" rowspan="" | |||||
valign="top" align="left"> | |||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | |||||
Stefan, others welcome | |||||
</font> | |||||
</td> | </td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
@@ -494,7 +473,28 @@ | |||||
<td bgcolor="#a0ddf0" colspan="" rowspan="" | <td bgcolor="#a0ddf0" colspan="" rowspan="" | ||||
valign="top" align="left"> | valign="top" align="left"> | ||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | <font color="#000000" size="-1" face="arial,helvetica,sanserif"> | ||||
Stefan, others welcome | |||||
Stefan | |||||
</font> | |||||
</td> | |||||
</tr> | |||||
<tr> | |||||
<td bgcolor="#a0ddf0" colspan="" rowspan="" | |||||
valign="top" align="left"> | |||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | |||||
JUnit's System.err/.out handling | |||||
</font> | |||||
</td> | |||||
<td bgcolor="#a0ddf0" colspan="" rowspan="" | |||||
valign="top" align="left"> | |||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | |||||
showoutput attribute has been added - doesn't work in | |||||
some cases yet (same reason as bug PR 7980) | |||||
</font> | |||||
</td> | |||||
<td bgcolor="#a0ddf0" colspan="" rowspan="" | |||||
valign="top" align="left"> | |||||
<font color="#000000" size="-1" face="arial,helvetica,sanserif"> | |||||
Stefan | |||||
</font> | </font> | ||||
</td> | </td> | ||||
</tr> | </tr> | ||||
@@ -135,6 +135,13 @@ elements</a>).</p> | |||||
the tests and JUnit to the classpath in forked mode.</td> | the tests and JUnit to the classpath in forked mode.</td> | ||||
<td align="center" valign="top">No; default is <code>true</code>.</td> | <td align="center" valign="top">No; default is <code>true</code>.</td> | ||||
</tr> | </tr> | ||||
<tr> | |||||
<td valign="top">showoutput</td> | |||||
<td valign="top">Send any output generated by tests to Ant's | |||||
logging system as well as to the formatters. By default only the | |||||
formatters receive the output.</td> | |||||
<td align="center" valign="top">No</td> | |||||
</tr> | |||||
</table> | </table> | ||||
<p>By using the <code>errorproperty</code> and <code>failureproperty</code> | <p>By using the <code>errorproperty</code> and <code>failureproperty</code> | ||||
@@ -1,34 +1,39 @@ | |||||
<?xml version="1.0"?> | <?xml version="1.0"?> | ||||
<project name="junit-test" basedir="." default="outputTests"> | <project name="junit-test" basedir="." default="outputTests"> | ||||
<property name="showoutput" value="false" /> | |||||
<path id="test"> | <path id="test"> | ||||
<pathelement path="${java.class.path}" /> | <pathelement path="${java.class.path}" /> | ||||
<pathelement location="../../../../../build/testcases" /> | <pathelement location="../../../../../build/testcases" /> | ||||
</path> | </path> | ||||
<target name="testForkedOutput"> | <target name="testForkedOutput"> | ||||
<junit fork="yes" haltonerror="true" haltonfailure="true"> | |||||
<junit fork="yes" haltonerror="true" haltonfailure="true" | |||||
showoutput="${showoutput}"> | |||||
<test name="org.example.junit.Output" /> | <test name="org.example.junit.Output" /> | ||||
<classpath refid="test" /> | <classpath refid="test" /> | ||||
</junit> | </junit> | ||||
</target> | </target> | ||||
<target name="testNonForkedOutput"> | <target name="testNonForkedOutput"> | ||||
<junit fork="false" haltonerror="true" haltonfailure="true"> | |||||
<junit fork="false" haltonerror="true" haltonfailure="true" | |||||
showoutput="${showoutput}"> | |||||
<test name="org.example.junit.Output" /> | <test name="org.example.junit.Output" /> | ||||
<classpath refid="test" /> | <classpath refid="test" /> | ||||
</junit> | </junit> | ||||
</target> | </target> | ||||
<target name="testForkedThreadedOutput"> | <target name="testForkedThreadedOutput"> | ||||
<junit fork="yes" haltonerror="true" haltonfailure="true"> | |||||
<junit fork="yes" haltonerror="true" haltonfailure="true" | |||||
showoutput="${showoutput}"> | |||||
<test name="org.example.junit.ThreadedOutput" /> | <test name="org.example.junit.ThreadedOutput" /> | ||||
<classpath refid="test" /> | <classpath refid="test" /> | ||||
</junit> | </junit> | ||||
</target> | </target> | ||||
<target name="testNonForkedThreadedOutput"> | <target name="testNonForkedThreadedOutput"> | ||||
<junit fork="false" haltonerror="true" haltonfailure="true"> | |||||
<junit fork="false" haltonerror="true" haltonfailure="true" | |||||
showoutput="${showoutput}"> | |||||
<test name="org.example.junit.ThreadedOutput" /> | <test name="org.example.junit.ThreadedOutput" /> | ||||
<classpath refid="test" /> | <classpath refid="test" /> | ||||
</junit> | </junit> | ||||
@@ -172,6 +172,8 @@ public class JUnitTask extends Task { | |||||
private boolean includeAntRuntime = true; | private boolean includeAntRuntime = true; | ||||
private Path antRuntimeClasses = null; | private Path antRuntimeClasses = null; | ||||
private boolean showOutput = false; | |||||
/** | /** | ||||
* Tells this task whether to smartly filter the stack frames of | * Tells this task whether to smartly filter the stack frames of | ||||
* JUnit testcase errors and failures before reporting them. | * JUnit testcase errors and failures before reporting them. | ||||
@@ -467,6 +469,20 @@ public class JUnitTask extends Task { | |||||
includeAntRuntime = b; | includeAntRuntime = b; | ||||
} | } | ||||
/** | |||||
* Whether to send output of the testcases to Ant's logging system or not. | |||||
* | |||||
* <p>Output will always be passed to the formatters and not by | |||||
* shown by default. This option should for example be set for | |||||
* tests that are interactive and prompt the user to do | |||||
* something.</p> | |||||
* | |||||
* @since Ant 1.5 | |||||
*/ | |||||
public void setShowOutput(boolean showOutput) { | |||||
this.showOutput = showOutput; | |||||
} | |||||
/** | /** | ||||
* Creates a new JUnitRunner and enables fork of a new Java VM. | * Creates a new JUnitRunner and enables fork of a new Java VM. | ||||
* | * | ||||
@@ -590,6 +606,9 @@ public class JUnitTask extends Task { | |||||
.setValue("formatter=org.apache.tools.ant.taskdefs.optional.junit.SummaryJUnitResultFormatter"); | .setValue("formatter=org.apache.tools.ant.taskdefs.optional.junit.SummaryJUnitResultFormatter"); | ||||
} | } | ||||
cmd.createArgument().setValue("showoutput=" | |||||
+ String.valueOf(showOutput)); | |||||
StringBuffer formatterArg = new StringBuffer(128); | StringBuffer formatterArg = new StringBuffer(128); | ||||
final FormatterElement[] feArray = mergeFormatters(test); | final FormatterElement[] feArray = mergeFormatters(test); | ||||
for (int i = 0; i < feArray.length; i++) { | for (int i = 0; i < feArray.length; i++) { | ||||
@@ -674,6 +693,9 @@ public class JUnitTask extends Task { | |||||
protected void handleOutput(String line) { | protected void handleOutput(String line) { | ||||
if (runner != null) { | if (runner != null) { | ||||
runner.handleOutput(line); | runner.handleOutput(line); | ||||
if (showOutput) { | |||||
super.handleOutput(line); | |||||
} | |||||
} else { | } else { | ||||
super.handleOutput(line); | super.handleOutput(line); | ||||
} | } | ||||
@@ -688,6 +710,9 @@ public class JUnitTask extends Task { | |||||
protected void handleErrorOutput(String line) { | protected void handleErrorOutput(String line) { | ||||
if (runner != null) { | if (runner != null) { | ||||
runner.handleErrorOutput(line); | runner.handleErrorOutput(line); | ||||
if (showOutput) { | |||||
super.handleErrorOutput(line); | |||||
} | |||||
} else { | } else { | ||||
super.handleErrorOutput(line); | super.handleErrorOutput(line); | ||||
} | } | ||||
@@ -65,19 +65,20 @@ import junit.framework.Test; | |||||
import junit.framework.TestSuite; | import junit.framework.TestSuite; | ||||
import junit.framework.AssertionFailedError; | import junit.framework.AssertionFailedError; | ||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
import java.io.BufferedReader; | import java.io.BufferedReader; | ||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | |||||
import java.io.OutputStream; | |||||
import java.io.PrintStream; | import java.io.PrintStream; | ||||
import java.io.PrintWriter; | import java.io.PrintWriter; | ||||
import java.io.StringReader; | import java.io.StringReader; | ||||
import java.io.StringWriter; | import java.io.StringWriter; | ||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.IOException; | |||||
import java.io.FileInputStream; | |||||
import java.io.File; | |||||
import java.util.Enumeration; | import java.util.Enumeration; | ||||
import java.util.Hashtable; | import java.util.Hashtable; | ||||
import java.util.Properties; | import java.util.Properties; | ||||
import java.util.Vector; | import java.util.Vector; | ||||
/** | /** | ||||
@@ -90,13 +91,15 @@ import java.util.Vector; | |||||
* public static junit.framework.Test suite() | * public static junit.framework.Test suite() | ||||
* </code></pre> | * </code></pre> | ||||
* | * | ||||
* <p> If no such method exists, all public methods starting with "test" and taking no | |||||
* argument will be run. | |||||
* <p> If no such method exists, all public methods starting with | |||||
* "test" and taking no argument will be run. | |||||
* | * | ||||
* <p> Summary output is generated at the end. | * <p> Summary output is generated at the end. | ||||
* | * | ||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | ||||
* @author <a href="mailto:ehatcher@apache.org">Erik Hatcher</a> | * @author <a href="mailto:ehatcher@apache.org">Erik Hatcher</a> | ||||
* | |||||
* @since Ant 1.2 | |||||
*/ | */ | ||||
public class JUnitTestRunner implements TestListener { | public class JUnitTestRunner implements TestListener { | ||||
@@ -131,6 +134,11 @@ public class JUnitTestRunner implements TestListener { | |||||
*/ | */ | ||||
private static boolean filtertrace = true; | private static boolean filtertrace = true; | ||||
/** | |||||
* Do we send output to System.out/.err in addition to the formatters? | |||||
*/ | |||||
private boolean showOutput = false; | |||||
private static final String[] DEFAULT_TRACE_FILTERS = new String[] { | private static final String[] DEFAULT_TRACE_FILTERS = new String[] { | ||||
"junit.framework.TestCase", | "junit.framework.TestCase", | ||||
"junit.framework.TestResult", | "junit.framework.TestResult", | ||||
@@ -187,20 +195,41 @@ public class JUnitTestRunner implements TestListener { | |||||
* Constructor for fork=true or when the user hasn't specified a | * Constructor for fork=true or when the user hasn't specified a | ||||
* classpath. | * classpath. | ||||
*/ | */ | ||||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, boolean filtertrace, | |||||
boolean haltOnFailure) { | |||||
this(test, haltOnError, filtertrace, haltOnFailure, null); | |||||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, | |||||
boolean filtertrace, boolean haltOnFailure) { | |||||
this(test, haltOnError, filtertrace, haltOnFailure, false); | |||||
} | |||||
/** | |||||
* Constructor for fork=true or when the user hasn't specified a | |||||
* classpath. | |||||
*/ | |||||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, | |||||
boolean filtertrace, boolean haltOnFailure, | |||||
boolean showOutput) { | |||||
this(test, haltOnError, filtertrace, haltOnFailure, showOutput, null); | |||||
} | } | ||||
/** | /** | ||||
* Constructor to use when the user has specified a classpath. | * Constructor to use when the user has specified a classpath. | ||||
*/ | */ | ||||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, boolean filtertrace, | |||||
boolean haltOnFailure, ClassLoader loader) { | |||||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, | |||||
boolean filtertrace, boolean haltOnFailure, | |||||
ClassLoader loader) { | |||||
this(test, haltOnError, filtertrace, haltOnFailure, false, loader); | |||||
} | |||||
/** | |||||
* Constructor to use when the user has specified a classpath. | |||||
*/ | |||||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, | |||||
boolean filtertrace, boolean haltOnFailure, | |||||
boolean showOutput, ClassLoader loader) { | |||||
this.filtertrace = filtertrace; | this.filtertrace = filtertrace; | ||||
this.junitTest = test; | this.junitTest = test; | ||||
this.haltOnError = haltOnError; | this.haltOnError = haltOnError; | ||||
this.haltOnFailure = haltOnFailure; | this.haltOnFailure = haltOnFailure; | ||||
this.showOutput = showOutput; | |||||
try { | try { | ||||
Class testClass = null; | Class testClass = null; | ||||
@@ -269,9 +298,26 @@ public class JUnitTestRunner implements TestListener { | |||||
if (forked) { | if (forked) { | ||||
savedOut = System.out; | savedOut = System.out; | ||||
System.setOut(systemOut); | |||||
savedErr = System.err; | savedErr = System.err; | ||||
System.setErr(systemError); | |||||
if (!showOutput) { | |||||
System.setOut(systemOut); | |||||
System.setErr(systemError); | |||||
} else { | |||||
System.setOut(new PrintStream( | |||||
new TeeOutputStream( | |||||
new OutputStream[] {savedOut, | |||||
systemOut} | |||||
) | |||||
) | |||||
); | |||||
System.setErr(new PrintStream( | |||||
new TeeOutputStream( | |||||
new OutputStream[] {savedErr, | |||||
systemError} | |||||
) | |||||
) | |||||
); | |||||
} | |||||
} | } | ||||
@@ -384,13 +430,15 @@ public class JUnitTestRunner implements TestListener { | |||||
private void fireStartTestSuite() { | private void fireStartTestSuite() { | ||||
for (int i = 0; i < formatters.size(); i++) { | for (int i = 0; i < formatters.size(); i++) { | ||||
((JUnitResultFormatter) formatters.elementAt(i)).startTestSuite(junitTest); | |||||
((JUnitResultFormatter) formatters.elementAt(i)) | |||||
.startTestSuite(junitTest); | |||||
} | } | ||||
} | } | ||||
private void fireEndTestSuite() { | private void fireEndTestSuite() { | ||||
for (int i = 0; i < formatters.size(); i++) { | for (int i = 0; i < formatters.size(); i++) { | ||||
((JUnitResultFormatter) formatters.elementAt(i)).endTestSuite(junitTest); | |||||
((JUnitResultFormatter) formatters.elementAt(i)) | |||||
.endTestSuite(junitTest); | |||||
} | } | ||||
} | } | ||||
@@ -417,6 +465,9 @@ public class JUnitTestRunner implements TestListener { | |||||
* classname,filename. If filename is ommitted, System.out is | * classname,filename. If filename is ommitted, System.out is | ||||
* assumed.</td><td>none</td></tr> | * assumed.</td><td>none</td></tr> | ||||
* | * | ||||
* <tr><td>showoutput</td><td>send output to System.err/.out as | |||||
* well as to the formatters?</td><td>false</td></tr> | |||||
* | |||||
* </table> | * </table> | ||||
*/ | */ | ||||
public static void main(String[] args) throws IOException { | public static void main(String[] args) throws IOException { | ||||
@@ -425,6 +476,7 @@ public class JUnitTestRunner implements TestListener { | |||||
boolean haltFail = false; | boolean haltFail = false; | ||||
boolean stackfilter = true; | boolean stackfilter = true; | ||||
Properties props = new Properties(); | Properties props = new Properties(); | ||||
boolean showOut = false; | |||||
if (args.length == 0) { | if (args.length == 0) { | ||||
System.err.println("required argument TestClassName missing"); | System.err.println("required argument TestClassName missing"); | ||||
@@ -446,9 +498,12 @@ public class JUnitTestRunner implements TestListener { | |||||
System.exit(ERRORS); | System.exit(ERRORS); | ||||
} | } | ||||
} else if (args[i].startsWith("propsfile=")) { | } else if (args[i].startsWith("propsfile=")) { | ||||
FileInputStream in = new FileInputStream(args[i].substring(10)); | |||||
FileInputStream in = new FileInputStream(args[i] | |||||
.substring(10)); | |||||
props.load(in); | props.load(in); | ||||
in.close(); | in.close(); | ||||
} else if (args[i].startsWith("showoutput=")) { | |||||
showOut = Project.toBoolean(args[i].substring(11)); | |||||
} | } | ||||
} | } | ||||
@@ -462,7 +517,8 @@ public class JUnitTestRunner implements TestListener { | |||||
} | } | ||||
t.setProperties(props); | t.setProperties(props); | ||||
JUnitTestRunner runner = new JUnitTestRunner(t, haltError, stackfilter, haltFail); | |||||
JUnitTestRunner runner = new JUnitTestRunner(t, haltError, stackfilter, | |||||
haltFail, showOut); | |||||
runner.forked = true; | runner.forked = true; | ||||
transferFormatters(runner); | transferFormatters(runner); | ||||
runner.run(); | runner.run(); | ||||
@@ -473,7 +529,8 @@ public class JUnitTestRunner implements TestListener { | |||||
private static void transferFormatters(JUnitTestRunner runner) { | private static void transferFormatters(JUnitTestRunner runner) { | ||||
for (int i = 0; i < fromCmdLine.size(); i++) { | for (int i = 0; i < fromCmdLine.size(); i++) { | ||||
runner.addFormatter((JUnitResultFormatter) fromCmdLine.elementAt(i)); | |||||
runner.addFormatter((JUnitResultFormatter) fromCmdLine | |||||
.elementAt(i)); | |||||
} | } | ||||
} | } | ||||
@@ -537,4 +594,25 @@ public class JUnitTestRunner implements TestListener { | |||||
return false; | return false; | ||||
} | } | ||||
/** | |||||
* Helper class that sends output sent to multiple streams. | |||||
* | |||||
* @since Ant 1.5 | |||||
*/ | |||||
private class TeeOutputStream extends OutputStream { | |||||
private OutputStream[] outs; | |||||
private TeeOutputStream(OutputStream[] outs) { | |||||
this.outs = outs; | |||||
} | |||||
public void write(int b) throws IOException { | |||||
for (int i = 0; i < outs.length; i++) { | |||||
outs[i].write(b); | |||||
} | |||||
} | |||||
} | |||||
} // JUnitTestRunner | } // JUnitTestRunner |
@@ -89,13 +89,6 @@ | |||||
<td>Stefan, others welcome</td> | <td>Stefan, others welcome</td> | ||||
</tr> | </tr> | ||||
<tr> | |||||
<td>JUnit's System.err/.out handling</td> | |||||
<td>Currently this is coupled to SummaryResultFormatter - | |||||
no SummaryFormatter, no output. Want to decouple it.</td> | |||||
<td>Stefan, others welcome</td> | |||||
</tr> | |||||
<tr> | <tr> | ||||
<td>Make javadoc a real directory based task</td> | <td>Make javadoc a real directory based task</td> | ||||
<td></td> | <td></td> | ||||
@@ -141,8 +134,15 @@ | |||||
<td>PGP signing task if possible</td> | <td>PGP signing task if possible</td> | ||||
<td>Not done, but deemed impossible - at least in the 1.5 | <td>Not done, but deemed impossible - at least in the 1.5 | ||||
time frame.</td> | time frame.</td> | ||||
<td>Stefan, others welcome</td> | |||||
<td>Stefan</td> | |||||
</tr> | |||||
<tr> | |||||
<td>JUnit's System.err/.out handling</td> | |||||
<td>showoutput attribute has been added - doesn't work in | |||||
some cases yet (same reason as bug PR 7980)</td> | |||||
<td>Stefan</td> | |||||
</tr> | </tr> | ||||
</table> | </table> | ||||
</subsection> | </subsection> | ||||