stack trace filtering for formatters. It will filter out those unneeded frame from Ant and JUnit so the stack will be much more readable. nb: Looks like the JUnit task need serious refactoring since we have been adding feature incrementally. It starts to be a real mess, I can barely read my own code :-( git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270099 13f79535-47bb-0310-9956-ffa450edef68master
@@ -60,12 +60,13 @@ import java.util.Vector; | |||
/** | |||
* Baseclass for BatchTest and JUnitTest. | |||
* | |||
* @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:sbailliez@imediation.com">Stephane Bailliez</a> | |||
*/ | |||
public abstract class BaseTest { | |||
protected boolean haltOnError = false; | |||
protected boolean haltOnFail = false; | |||
protected boolean filtertrace = true; | |||
protected boolean fork = false; | |||
protected String ifProperty = null; | |||
protected String unlessProperty = null; | |||
@@ -76,6 +77,14 @@ public abstract class BaseTest { | |||
protected String failureProperty; | |||
protected String errorProperty; | |||
public void setFiltertrace(boolean value) { | |||
filtertrace = value; | |||
} | |||
public boolean getFiltertrace() { | |||
return filtertrace; | |||
} | |||
public void setFork(boolean value) { | |||
fork = value; | |||
} | |||
@@ -116,12 +125,12 @@ public abstract class BaseTest { | |||
* Sets the destination directory. | |||
*/ | |||
public void setTodir(File destDir) { | |||
this.destDir = destDir; | |||
this.destDir = destDir; | |||
} | |||
/** | |||
* @return the destination directory as an absolute path if it exists | |||
* otherwise return <tt>null</tt> | |||
* otherwise return <tt>null</tt> | |||
*/ | |||
public String getTodir(){ | |||
if (destDir != null){ | |||
@@ -133,15 +142,15 @@ public abstract class BaseTest { | |||
public java.lang.String getFailureProperty() { | |||
return failureProperty; | |||
} | |||
public void setFailureProperty(String failureProperty) { | |||
this.failureProperty = failureProperty; | |||
} | |||
public java.lang.String getErrorProperty() { | |||
return errorProperty; | |||
} | |||
public void setErrorProperty(String errorProperty) { | |||
this.errorProperty = errorProperty; | |||
} | |||
@@ -199,6 +199,7 @@ public final class BatchTest extends BaseTest { | |||
test.setName(classname); | |||
test.setHaltonerror(this.haltOnError); | |||
test.setHaltonfailure(this.haltOnFail); | |||
test.setFiltertrace(this.filtertrace); | |||
test.setFork(this.fork); | |||
test.setIf(this.ifProperty); | |||
test.setUnless(this.unlessProperty); | |||
@@ -155,7 +155,23 @@ public class JUnitTask extends Task { | |||
private Integer timeout = null; | |||
private boolean summary = false; | |||
private String summaryValue = ""; | |||
private boolean filtertrace = true; | |||
private JUnitTestRunner runner = null; | |||
/** | |||
* Tells this task whether to smartly filter the stack frames of JUnit testcase | |||
* errors and failures before reporting them. This property is applied on all | |||
* BatchTest (batchtest) and JUnitTest (test) however it can possibly be | |||
* overridden by their own properties. | |||
* @param value <tt>false</tt> if it should not filter, otherwise <tt>true<tt> | |||
*/ | |||
public void setFiltertrace(boolean value) { | |||
Enumeration enum = allTests(); | |||
while (enum.hasMoreElements()) { | |||
BaseTest test = (BaseTest) enum.nextElement(); | |||
test.setFiltertrace(value); | |||
} | |||
} | |||
/** | |||
* Tells this task to halt when there is an error in a test. | |||
@@ -361,7 +377,7 @@ public class JUnitTask extends Task { | |||
/** | |||
* Adds the jars or directories containing Ant, this task and | |||
* JUnit to the classpath - this should make the forked JVM work | |||
* without having to specify the directly. | |||
* without having to specify them directly. | |||
*/ | |||
public void init() { | |||
addClasspathEntry("/junit/framework/TestCase.class"); | |||
@@ -447,6 +463,7 @@ public class JUnitTask extends Task { | |||
cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner"); | |||
cmd.createArgument().setValue(test.getName()); | |||
cmd.createArgument().setValue("filtertrace=" + test.getFiltertrace()); | |||
cmd.createArgument().setValue("haltOnError=" + test.getHaltonerror()); | |||
cmd.createArgument().setValue("haltOnFailure=" + test.getHaltonfailure()); | |||
if (summary) { | |||
@@ -555,8 +572,7 @@ public class JUnitTask extends Task { | |||
// will cause trouble in JDK 1.1 if omitted | |||
cl.addSystemPackageRoot("org.apache.tools.ant"); | |||
} | |||
runner = new JUnitTestRunner(test, test.getHaltonerror(), test.getHaltonfailure(), cl); | |||
runner = new JUnitTestRunner(test, test.getHaltonerror(), test.getFiltertrace(), test.getHaltonfailure(), cl); | |||
if (summary) { | |||
log("Running " + test.getName(), Project.MSG_INFO); | |||
@@ -100,10 +100,11 @@ public class JUnitTest extends BaseTest { | |||
this.name = name; | |||
} | |||
public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure) { | |||
public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure, boolean filtertrace) { | |||
this.name = name; | |||
this.haltOnError = haltOnError; | |||
this.haltOnFail = haltOnFail; | |||
this.haltOnFail = haltOnFailure; | |||
this.filtertrace = filtertrace; | |||
} | |||
/** | |||
@@ -64,7 +64,11 @@ import junit.framework.Test; | |||
import junit.framework.TestSuite; | |||
import junit.framework.AssertionFailedError; | |||
import java.lang.reflect.Method; | |||
import java.io.BufferedReader; | |||
import java.io.PrintStream; | |||
import java.io.PrintWriter; | |||
import java.io.StringReader; | |||
import java.io.StringWriter; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.FileInputStream; | |||
@@ -121,6 +125,24 @@ public class JUnitTestRunner implements TestListener { | |||
*/ | |||
private TestResult res; | |||
/** | |||
* Do we filter junit.*.* stack frames out of failure and error exceptions. | |||
*/ | |||
private static boolean filtertrace = true; | |||
private final static String[] DEFAULT_TRACE_FILTERS = new String[] { | |||
"junit.framework.TestCase", | |||
"junit.framework.TestResult", | |||
"junit.framework.TestSuite", | |||
"junit.framework.Assert.", // don't filter AssertionFailure | |||
"junit.swingui.TestRunner", | |||
"junit.awtui.TestRunner", | |||
"junit.textui.TestRunner", | |||
"java.lang.reflect.Method.invoke(", | |||
"org.apache.tools.ant." | |||
}; | |||
/** | |||
* Do we stop on errors. | |||
*/ | |||
@@ -161,16 +183,18 @@ public class JUnitTestRunner implements TestListener { | |||
* Constructor for fork=true or when the user hasn't specified a | |||
* classpath. | |||
*/ | |||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, | |||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, boolean filtertrace, | |||
boolean haltOnFailure) { | |||
this(test, haltOnError, haltOnFailure, null); | |||
this(test, haltOnError, filtertrace, haltOnFailure, null); | |||
} | |||
/** | |||
* Constructor to use when the user has specified a classpath. | |||
*/ | |||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, | |||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, boolean filtertrace, | |||
boolean haltOnFailure, ClassLoader loader) { | |||
//JUnitTestRunner.filtertrace = filtertrace; | |||
this.filtertrace = filtertrace; | |||
this.junitTest = test; | |||
this.haltOnError = haltOnError; | |||
this.haltOnFailure = haltOnFailure; | |||
@@ -378,6 +402,7 @@ public class JUnitTestRunner implements TestListener { | |||
boolean exitAtEnd = true; | |||
boolean haltError = false; | |||
boolean haltFail = false; | |||
boolean stackfilter = true; | |||
Properties props = new Properties(); | |||
if (args.length == 0) { | |||
@@ -390,6 +415,8 @@ public class JUnitTestRunner implements TestListener { | |||
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("filtertrace=")) { | |||
stackfilter = Project.toBoolean(args[i].substring(12)); | |||
} else if (args[i].startsWith("formatter=")) { | |||
try { | |||
createAndStoreFormatter(args[i].substring(10)); | |||
@@ -405,7 +432,7 @@ public class JUnitTestRunner implements TestListener { | |||
} | |||
JUnitTest t = new JUnitTest(args[0]); | |||
// Add/overlay system properties on the properties from the Ant project | |||
Hashtable p = System.getProperties(); | |||
for (Enumeration enum = p.keys(); enum.hasMoreElements(); ) { | |||
@@ -414,7 +441,7 @@ public class JUnitTestRunner implements TestListener { | |||
} | |||
t.setProperties(props); | |||
JUnitTestRunner runner = new JUnitTestRunner(t, haltError, haltFail); | |||
JUnitTestRunner runner = new JUnitTestRunner(t, haltError, stackfilter, haltFail); | |||
transferFormatters(runner); | |||
runner.run(); | |||
System.exit(runner.getRetCode()); | |||
@@ -443,5 +470,53 @@ public class JUnitTestRunner implements TestListener { | |||
} | |||
fromCmdLine.addElement(fe.createFormatter()); | |||
} | |||
/** | |||
* Returns a filtered stack trace. | |||
* This is ripped out of junit.runner.BaseTestRunner. | |||
* Scott M. Stirling. | |||
*/ | |||
public static String getFilteredTrace(Throwable t) { | |||
StringWriter stringWriter = new StringWriter(); | |||
PrintWriter writer = new PrintWriter(stringWriter); | |||
t.printStackTrace(writer); | |||
StringBuffer buffer = stringWriter.getBuffer(); | |||
String trace = buffer.toString(); | |||
return JUnitTestRunner.filterStack(trace); | |||
} | |||
/** | |||
* Filters stack frames from internal JUnit and Ant classes | |||
*/ | |||
public static String filterStack(String stack) { | |||
if (!filtertrace) { | |||
return stack; | |||
} | |||
StringWriter sw = new StringWriter(); | |||
PrintWriter pw = new PrintWriter(sw); | |||
StringReader sr = new StringReader(stack); | |||
BufferedReader br = new BufferedReader(sr); | |||
String line; | |||
try { | |||
while ((line = br.readLine()) != null) { | |||
if (!filterLine(line)) { | |||
pw.println(line); | |||
} | |||
} | |||
} catch (Exception IOException) { | |||
return stack; // return the stack unfiltered | |||
} | |||
return sw.toString(); | |||
} | |||
private static boolean filterLine(String line) { | |||
for (int i = 0; i < DEFAULT_TRACE_FILTERS.length; i++) { | |||
if (line.indexOf(DEFAULT_TRACE_FILTERS[i]) > 0) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
} // JUnitTestRunner |
@@ -248,7 +248,8 @@ public class PlainJUnitResultFormatter implements JUnitResultFormatter { | |||
wri.println(type); | |||
wri.println(t.getMessage()); | |||
t.printStackTrace(wri); | |||
String strace = JUnitTestRunner.getFilteredTrace(t); | |||
wri.print(strace); | |||
wri.println(""); | |||
} | |||
} | |||
@@ -261,9 +261,8 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstan | |||
} | |||
nested.setAttribute(ATTR_TYPE, t.getClass().getName()); | |||
StringWriter swr = new StringWriter(); | |||
t.printStackTrace(new PrintWriter(swr, true)); | |||
Text trace = doc.createTextNode(swr.toString()); | |||
String strace = JUnitTestRunner.getFilteredTrace(t); | |||
Text trace = doc.createTextNode(strace); | |||
nested.appendChild(trace); | |||
} | |||