present in <classpath> even if not among Ant libs. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@381467 13f79535-47bb-0310-9956-ffa450edef68master
@@ -1,4 +1,4 @@ | |||||
Changes from current Ant 1.6.5 version to current RCS version | |||||
Changes from current Ant 1.6.5 version to current SVN version | |||||
============================================================= | ============================================================= | ||||
Changes that could break older environments: | Changes that could break older environments: | ||||
@@ -77,6 +77,8 @@ Changes that could break older environments: | |||||
Fixed bugs: | Fixed bugs: | ||||
----------- | ----------- | ||||
* <junit> can now work with junit.jar in its <classpath>. Bugzilla Report 38799. | |||||
* Some potential NullPointerExceptions, Bugzilla Reports 37765 and 38056 | * Some potential NullPointerExceptions, Bugzilla Reports 37765 and 38056 | ||||
* Problem when adding multiple filter files, Bugzilla Report 37341 | * Problem when adding multiple filter files, Bugzilla Report 37341 | ||||
@@ -19,12 +19,12 @@ Library Dependencies</a> for more information. | |||||
</p> | </p> | ||||
<p> | <p> | ||||
<strong>Note</strong>: | <strong>Note</strong>: | ||||
You must have <code>junit.jar</code> and the class files for the | |||||
<code><junit></code> task in the same classpath. | |||||
You must have <code>junit.jar</code> available. | |||||
You can do one of: | You can do one of: | ||||
</p> | |||||
<ol> | <ol> | ||||
<li> | <li> | ||||
Put both <code>junit.jar</code> and the optional tasks jar file in | |||||
Put both <code>junit.jar</code> and <code>ant-junit.jar</code> in | |||||
<code>ANT_HOME/lib</code>. | <code>ANT_HOME/lib</code>. | ||||
</li> | </li> | ||||
<li> | <li> | ||||
@@ -32,15 +32,23 @@ Do not put either in <code>ANT_HOME/lib</code>, and instead | |||||
include their locations in your <code>CLASSPATH</code> environment variable. | include their locations in your <code>CLASSPATH</code> environment variable. | ||||
</li> | </li> | ||||
<li> | <li> | ||||
Do neither of the above, and instead, specify their locations using | |||||
a <code><classpath></code> element in the build file. | |||||
Add both JARs to your classpath using <code>-lib</code>. | |||||
</li> | |||||
<li> | |||||
Specify the locations of both JARs using | |||||
a <code><classpath></code> element in a <code><taskdef></code> in the build file. | |||||
</li> | |||||
<li> | |||||
Leave <code>ant-junit.jar</code> in its default location in <code>ANT_HOME/lib</code> | |||||
but include <code>junit.jar</code> in the <code><classpath></code> passed | |||||
to <code><junit></code>. <em>(since Ant 1.7)</em> | |||||
</li> | |||||
</ol> | |||||
<p> | |||||
See <a href="../../faq.html#delegating-classloader" target="_top">the | See <a href="../../faq.html#delegating-classloader" target="_top">the | ||||
FAQ</a> for details. | FAQ</a> for details. | ||||
</ol> | |||||
</p> | </p> | ||||
<p>Tests are defined by nested <code>test</code> or | <p>Tests are defined by nested <code>test</code> or | ||||
<code>batchtest</code> tags (see <a href="#nested">nested | <code>batchtest</code> tags (see <a href="#nested">nested | ||||
elements</a>).</p> | elements</a>).</p> | ||||
@@ -217,6 +225,9 @@ supports a nested <code><classpath></code> | |||||
element that represents a <a href="../using.html#path">PATH like | element that represents a <a href="../using.html#path">PATH like | ||||
structure</a>.</p> | structure</a>.</p> | ||||
<p>As of Ant 1.7, this classpath may be used to refer to <code>junit.jar</code> | |||||
as well as your tests and the tested code. | |||||
<h4>jvmarg</h4> | <h4>jvmarg</h4> | ||||
<p>If <code>fork</code> is enabled, additional parameters may be passed to | <p>If <code>fork</code> is enabled, additional parameters may be passed to | ||||
@@ -580,7 +591,7 @@ aborted. Results are collected in files named | |||||
<code>${reports.tests}</code>.</p> | <code>${reports.tests}</code>.</p> | ||||
<hr> | <hr> | ||||
<p align="center">Copyright © 2000-2005 The Apache Software Foundation. All rights | |||||
<p align="center">Copyright © 2000-2006 The Apache Software Foundation. All rights | |||||
Reserved.</p> | Reserved.</p> | ||||
</body> | </body> | ||||
</html> | </html> |
@@ -456,7 +456,7 @@ you need jakarta-oro 2.0.1 or later, and <a href="#commons-net">commons-net</a>< | |||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
<td>junit.jar</td> | <td>junit.jar</td> | ||||
<td>junit tasks</td> | |||||
<td><code><junit></code> task. May be in classpath passed to task rather than Ant's classpath.</td> | |||||
<td><a href="http://www.junit.org/" target="_top">http://www.junit.org/</a></td> | <td><a href="http://www.junit.org/" target="_top">http://www.junit.org/</a></td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
@@ -698,7 +698,7 @@ advised to do it by the user mailing list. | |||||
<hr> | <hr> | ||||
<p align="center">Copyright © 2000-2005 The Apache Software Foundation. All rights | |||||
<p align="center">Copyright © 2000-2006 The Apache Software Foundation. All rights | |||||
Reserved.</p> | Reserved.</p> | ||||
</body> | </body> | ||||
@@ -1,5 +1,5 @@ | |||||
/* | /* | ||||
* Copyright 2000-2005 The Apache Software Foundation | |||||
* Copyright 2000-2006 The Apache Software Foundation | |||||
* | * | ||||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
@@ -1490,4 +1490,8 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { | |||||
} | } | ||||
} | } | ||||
public String toString() { | |||||
return "AntClassLoader[" + getClasspath() + "]"; | |||||
} | |||||
} | } |
@@ -1,5 +1,5 @@ | |||||
/* | /* | ||||
* Copyright 2001-2004 The Apache Software Foundation | |||||
* Copyright 2001-2004,2006 The Apache Software Foundation | |||||
* | * | ||||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
@@ -188,14 +188,14 @@ public class FormatterElement { | |||||
/** | /** | ||||
* @since Ant 1.2 | * @since Ant 1.2 | ||||
*/ | */ | ||||
JUnitResultFormatter createFormatter() throws BuildException { | |||||
JUnitTaskMirror.JUnitResultFormatterMirror createFormatter() throws BuildException { | |||||
return createFormatter(null); | return createFormatter(null); | ||||
} | } | ||||
/** | /** | ||||
* @since Ant 1.6 | * @since Ant 1.6 | ||||
*/ | */ | ||||
JUnitResultFormatter createFormatter(ClassLoader loader) | |||||
JUnitTaskMirror.JUnitResultFormatterMirror createFormatter(ClassLoader loader) | |||||
throws BuildException { | throws BuildException { | ||||
if (classname == null) { | if (classname == null) { | ||||
@@ -210,7 +210,9 @@ public class FormatterElement { | |||||
f = Class.forName(classname, true, loader); | f = Class.forName(classname, true, loader); | ||||
} | } | ||||
} catch (ClassNotFoundException e) { | } catch (ClassNotFoundException e) { | ||||
throw new BuildException(e); | |||||
throw new BuildException("Using loader " + loader + " on class " + classname + ": " + e, e); | |||||
} catch (NoClassDefFoundError e) { | |||||
throw new BuildException("Using loader " + loader + " on class " + classname + ": " + e, e); | |||||
} | } | ||||
Object o = null; | Object o = null; | ||||
@@ -222,12 +224,11 @@ public class FormatterElement { | |||||
throw new BuildException(e); | throw new BuildException(e); | ||||
} | } | ||||
if (!(o instanceof JUnitResultFormatter)) { | |||||
if (!(o instanceof JUnitTaskMirror.JUnitResultFormatterMirror)) { | |||||
throw new BuildException(classname | throw new BuildException(classname | ||||
+ " is not a JUnitResultFormatter"); | + " is not a JUnitResultFormatter"); | ||||
} | } | ||||
JUnitResultFormatter r = (JUnitResultFormatter) o; | |||||
JUnitTaskMirror.JUnitResultFormatterMirror r = (JUnitTaskMirror.JUnitResultFormatterMirror) o; | |||||
if (useFile && outFile != null) { | if (useFile && outFile != null) { | ||||
try { | try { | ||||
@@ -1,5 +1,5 @@ | |||||
/* | /* | ||||
* Copyright 2001-2002,2004 The Apache Software Foundation | |||||
* Copyright 2001-2002,2004,2006 The Apache Software Foundation | |||||
* | * | ||||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
@@ -26,7 +26,7 @@ import org.apache.tools.ant.BuildException; | |||||
* testrun. | * testrun. | ||||
* | * | ||||
*/ | */ | ||||
public interface JUnitResultFormatter extends TestListener { | |||||
public interface JUnitResultFormatter extends TestListener, JUnitTaskMirror.JUnitResultFormatterMirror { | |||||
/** | /** | ||||
* The whole testsuite started. | * The whole testsuite started. | ||||
*/ | */ | ||||
@@ -24,6 +24,7 @@ import java.io.FileWriter; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.io.PrintWriter; | import java.io.PrintWriter; | ||||
import java.lang.reflect.Constructor; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collection; | import java.util.Collection; | ||||
import java.util.Enumeration; | import java.util.Enumeration; | ||||
@@ -34,9 +35,6 @@ import java.util.List; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Properties; | import java.util.Properties; | ||||
import java.util.Vector; | import java.util.Vector; | ||||
import junit.framework.AssertionFailedError; | |||||
import junit.framework.Test; | |||||
import junit.framework.TestResult; | |||||
import org.apache.tools.ant.AntClassLoader; | import org.apache.tools.ant.AntClassLoader; | ||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
@@ -134,7 +132,7 @@ public class JUnitTask extends Task { | |||||
private boolean summary = false; | private boolean summary = false; | ||||
private boolean reloading = true; | private boolean reloading = true; | ||||
private String summaryValue = ""; | private String summaryValue = ""; | ||||
private JUnitTestRunner runner = null; | |||||
private JUnitTaskMirror.JUnitTestRunnerMirror runner = null; | |||||
private boolean newEnvironment = false; | private boolean newEnvironment = false; | ||||
private Environment env = new Environment(); | private Environment env = new Environment(); | ||||
@@ -148,6 +146,9 @@ public class JUnitTask extends Task { | |||||
private Permissions perm = null; | private Permissions perm = null; | ||||
private ForkMode forkMode = new ForkMode("perTest"); | private ForkMode forkMode = new ForkMode("perTest"); | ||||
private boolean splitJunit = false; | |||||
private JUnitTaskMirror delegate; | |||||
private static final int STRING_BUFFER_SIZE = 128; | private static final int STRING_BUFFER_SIZE = 128; | ||||
/** | /** | ||||
* @since Ant 1.7 | * @since Ant 1.7 | ||||
@@ -632,12 +633,81 @@ public class JUnitTask extends Task { | |||||
*/ | */ | ||||
public void init() { | public void init() { | ||||
antRuntimeClasses = new Path(getProject()); | antRuntimeClasses = new Path(getProject()); | ||||
addClasspathEntry("/junit/framework/TestCase.class"); | |||||
splitJunit = !addClasspathEntry("/junit/framework/TestCase.class"); | |||||
addClasspathEntry("/org/apache/tools/ant/launch/AntMain.class"); | addClasspathEntry("/org/apache/tools/ant/launch/AntMain.class"); | ||||
addClasspathEntry("/org/apache/tools/ant/Task.class"); | addClasspathEntry("/org/apache/tools/ant/Task.class"); | ||||
addClasspathEntry("/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.class"); | addClasspathEntry("/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.class"); | ||||
} | } | ||||
private static JUnitTaskMirror createMirror(JUnitTask task, ClassLoader loader) { | |||||
try { | |||||
loader.loadClass("junit.framework.Test"); // sanity check | |||||
} catch (ClassNotFoundException e) { | |||||
throw new BuildException( | |||||
"The <classpath> for <junit> must include junit.jar if not in Ant's own classpath", | |||||
e, task.getLocation()); | |||||
} | |||||
try { | |||||
Class c = loader.loadClass(JUnitTaskMirror.class.getName() + "Impl"); | |||||
if (c.getClassLoader() != loader) { | |||||
throw new BuildException("Overdelegating loader", task.getLocation()); | |||||
} | |||||
Constructor cons = c.getConstructor(new Class[] {JUnitTask.class}); | |||||
return (JUnitTaskMirror) cons.newInstance(new Object[] {task}); | |||||
} catch (Exception e) { | |||||
throw new BuildException(e, task.getLocation()); | |||||
} | |||||
} | |||||
private final class SplitLoader extends AntClassLoader { | |||||
public SplitLoader(ClassLoader parent, Path path) { | |||||
super(parent, getProject(), path, true); | |||||
} | |||||
// forceLoadClass is not convenient here since it would not | |||||
// properly deal with inner classes of these classes. | |||||
protected synchronized Class loadClass(String classname, boolean resolve) | |||||
throws ClassNotFoundException { | |||||
Class theClass = findLoadedClass(classname); | |||||
if (theClass != null) { | |||||
return theClass; | |||||
} | |||||
if (isSplit(classname)) { | |||||
theClass = findClass(classname); | |||||
if (resolve) { | |||||
resolveClass(theClass); | |||||
} | |||||
return theClass; | |||||
} else { | |||||
return super.loadClass(classname, resolve); | |||||
} | |||||
} | |||||
private final String[] SPLIT_CLASSES = { | |||||
"BriefJUnitResultFormatter", | |||||
"JUnitResultFormatter", | |||||
"JUnitTaskMirrorImpl", | |||||
"JUnitTestRunner", | |||||
"JUnitVersionHelper", | |||||
"OutErrSummaryJUnitResultFormatter", | |||||
"PlainJUnitResultFormatter", | |||||
"SummaryJUnitResultFormatter", | |||||
"XMLJUnitResultFormatter", | |||||
}; | |||||
private boolean isSplit(String classname) { | |||||
String simplename = classname.substring(classname.lastIndexOf('.') + 1); | |||||
for (int i = 0; i < SPLIT_CLASSES.length; i++) { | |||||
if (simplename.equals(SPLIT_CLASSES[i]) || simplename.startsWith(SPLIT_CLASSES[i] + '$')) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
} | |||||
/** | /** | ||||
* Runs the testcase. | * Runs the testcase. | ||||
* | * | ||||
@@ -645,6 +715,18 @@ public class JUnitTask extends Task { | |||||
* @since Ant 1.2 | * @since Ant 1.2 | ||||
*/ | */ | ||||
public void execute() throws BuildException { | public void execute() throws BuildException { | ||||
ClassLoader myLoader = JUnitTask.class.getClassLoader(); | |||||
ClassLoader mirrorLoader; | |||||
if (splitJunit) { | |||||
Path path = new Path(getProject()); | |||||
path.add(antRuntimeClasses); | |||||
path.add(getCommandline().getClasspath()); | |||||
mirrorLoader = new SplitLoader(myLoader, path); | |||||
} else { | |||||
mirrorLoader = myLoader; | |||||
} | |||||
delegate = createMirror(this, mirrorLoader); | |||||
List testLists = new ArrayList(); | List testLists = new ArrayList(); | ||||
boolean forkPerTest = forkMode.getValue().equals(ForkMode.PER_TEST); | boolean forkPerTest = forkMode.getValue().equals(ForkMode.PER_TEST); | ||||
@@ -672,6 +754,10 @@ public class JUnitTask extends Task { | |||||
} | } | ||||
} finally { | } finally { | ||||
deleteClassLoader(); | deleteClassLoader(); | ||||
if (mirrorLoader instanceof SplitLoader) { | |||||
((SplitLoader) mirrorLoader).cleanup(); | |||||
} | |||||
delegate = null; | |||||
} | } | ||||
} | } | ||||
@@ -1061,18 +1147,22 @@ public class JUnitTask extends Task { | |||||
try { | try { | ||||
log("Using System properties " + System.getProperties(), | log("Using System properties " + System.getProperties(), | ||||
Project.MSG_VERBOSE); | Project.MSG_VERBOSE); | ||||
createClassLoader(); | |||||
if (splitJunit) { | |||||
classLoader = (AntClassLoader) delegate.getClass().getClassLoader(); | |||||
} else { | |||||
createClassLoader(); | |||||
} | |||||
if (classLoader != null) { | if (classLoader != null) { | ||||
classLoader.setThreadContextLoader(); | classLoader.setThreadContextLoader(); | ||||
} | } | ||||
runner = new JUnitTestRunner(test, test.getHaltonerror(), | |||||
runner = delegate.newJUnitTestRunner(test, test.getHaltonerror(), | |||||
test.getFiltertrace(), | test.getFiltertrace(), | ||||
test.getHaltonfailure(), false, | test.getHaltonfailure(), false, | ||||
true, classLoader); | true, classLoader); | ||||
if (summary) { | if (summary) { | ||||
SummaryJUnitResultFormatter f = | |||||
new SummaryJUnitResultFormatter(); | |||||
JUnitTaskMirror.SummaryJUnitResultFormatterMirror f = | |||||
delegate.newSummaryJUnitResultFormatter(); | |||||
f.setWithOutAndErr("withoutanderr" | f.setWithOutAndErr("withoutanderr" | ||||
.equalsIgnoreCase(summaryValue)); | .equalsIgnoreCase(summaryValue)); | ||||
f.setOutput(getDefaultOutput()); | f.setOutput(getDefaultOutput()); | ||||
@@ -1186,7 +1276,7 @@ public class JUnitTask extends Task { | |||||
if (fe.getUseFile()) { | if (fe.getUseFile()) { | ||||
String base = test.getOutfile(); | String base = test.getOutfile(); | ||||
if (base == null) { | if (base == null) { | ||||
base = JUnitTestRunner.IGNORED_FILE_NAME; | |||||
base = JUnitTaskMirror.JUnitTestRunnerMirror.IGNORED_FILE_NAME; | |||||
} | } | ||||
String filename = base + fe.getExtension(); | String filename = base + fe.getExtension(); | ||||
File destFile = new File(test.getTodir(), filename); | File destFile = new File(test.getTodir(), filename); | ||||
@@ -1204,9 +1294,10 @@ public class JUnitTask extends Task { | |||||
* getResource doesn't contain the name of the archive.</p> | * getResource doesn't contain the name of the archive.</p> | ||||
* | * | ||||
* @param resource resource that one wants to lookup | * @param resource resource that one wants to lookup | ||||
* @return true if something was in fact added | |||||
* @since Ant 1.4 | * @since Ant 1.4 | ||||
*/ | */ | ||||
protected void addClasspathEntry(String resource) { | |||||
protected boolean addClasspathEntry(String resource) { | |||||
/* | /* | ||||
* pre Ant 1.6 this method used to call getClass().getResource | * pre Ant 1.6 this method used to call getClass().getResource | ||||
* while Ant 1.6 will call ClassLoader.getResource(). | * while Ant 1.6 will call ClassLoader.getResource(). | ||||
@@ -1228,8 +1319,10 @@ public class JUnitTask extends Task { | |||||
if (f != null) { | if (f != null) { | ||||
log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG); | log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG); | ||||
antRuntimeClasses.createPath().setLocation(f); | antRuntimeClasses.createPath().setLocation(f); | ||||
return true; | |||||
} else { | } else { | ||||
log("Couldn\'t find " + resource, Project.MSG_DEBUG); | log("Couldn\'t find " + resource, Project.MSG_DEBUG); | ||||
return false; | |||||
} | } | ||||
} | } | ||||
@@ -1269,7 +1362,7 @@ public class JUnitTask extends Task { | |||||
for (int i = 0; i < feArray.length; i++) { | for (int i = 0; i < feArray.length; i++) { | ||||
FormatterElement fe = feArray[i]; | FormatterElement fe = feArray[i]; | ||||
File outFile = getOutput(fe, test); | File outFile = getOutput(fe, test); | ||||
JUnitResultFormatter formatter = fe.createFormatter(classLoader); | |||||
JUnitTaskMirror.JUnitResultFormatterMirror formatter = fe.createFormatter(classLoader); | |||||
if (outFile != null && formatter != null) { | if (outFile != null && formatter != null) { | ||||
try { | try { | ||||
OutputStream out = new FileOutputStream(outFile); | OutputStream out = new FileOutputStream(outFile); | ||||
@@ -1280,7 +1373,7 @@ public class JUnitTask extends Task { | |||||
} | } | ||||
} | } | ||||
if (summary) { | if (summary) { | ||||
SummaryJUnitResultFormatter f = new SummaryJUnitResultFormatter(); | |||||
JUnitTaskMirror.SummaryJUnitResultFormatterMirror f = delegate.newSummaryJUnitResultFormatter(); | |||||
f.setWithOutAndErr("withoutanderr".equalsIgnoreCase(summaryValue)); | f.setWithOutAndErr("withoutanderr".equalsIgnoreCase(summaryValue)); | ||||
addVmExit(test, f, getDefaultOutput(), message); | addVmExit(test, f, getDefaultOutput(), message); | ||||
} | } | ||||
@@ -1291,23 +1384,9 @@ public class JUnitTask extends Task { | |||||
* Only used from the logVmExit method. | * Only used from the logVmExit method. | ||||
* @since Ant 1.7 | * @since Ant 1.7 | ||||
*/ | */ | ||||
private void addVmExit(JUnitTest test, JUnitResultFormatter formatter, | |||||
private void addVmExit(JUnitTest test, JUnitTaskMirror.JUnitResultFormatterMirror formatter, | |||||
OutputStream out, final String message) { | OutputStream out, final String message) { | ||||
formatter.setOutput(out); | |||||
formatter.startTestSuite(test); | |||||
//the trick to integrating test output to the formatter, is to | |||||
//create a special test class that asserts an error | |||||
//and tell the formatter that it raised. | |||||
Test t = new Test() { | |||||
public int countTestCases() { return 1; } | |||||
public void run(TestResult r) { | |||||
throw new AssertionFailedError(message); | |||||
} | |||||
}; | |||||
formatter.startTest(t); | |||||
formatter.addError(t, new AssertionFailedError(message)); | |||||
formatter.endTestSuite(test); | |||||
delegate.addVmExit(test, formatter, out, message); | |||||
} | } | ||||
/** | /** | ||||
@@ -1535,9 +1614,9 @@ public class JUnitTask extends Task { | |||||
// everything otherwise just log a statement | // everything otherwise just log a statement | ||||
boolean fatal = result.timedOut || result.crashed; | boolean fatal = result.timedOut || result.crashed; | ||||
boolean errorOccurredHere = | boolean errorOccurredHere = | ||||
result.exitCode == JUnitTestRunner.ERRORS || fatal; | |||||
result.exitCode == JUnitTaskMirror.JUnitTestRunnerMirror.ERRORS || fatal; | |||||
boolean failureOccurredHere = | boolean failureOccurredHere = | ||||
result.exitCode != JUnitTestRunner.SUCCESS || fatal; | |||||
result.exitCode != JUnitTaskMirror.JUnitTestRunnerMirror.SUCCESS || fatal; | |||||
if (errorOccurredHere || failureOccurredHere) { | if (errorOccurredHere || failureOccurredHere) { | ||||
if ((errorOccurredHere && test.getHaltonerror()) | if ((errorOccurredHere && test.getHaltonerror()) | ||||
|| (failureOccurredHere && test.getHaltonfailure())) { | || (failureOccurredHere && test.getHaltonfailure())) { | ||||
@@ -1559,7 +1638,7 @@ public class JUnitTask extends Task { | |||||
} | } | ||||
protected class TestResultHolder { | protected class TestResultHolder { | ||||
public int exitCode = JUnitTestRunner.ERRORS; | |||||
public int exitCode = JUnitTaskMirror.JUnitTestRunnerMirror.ERRORS; | |||||
public boolean timedOut = false; | public boolean timedOut = false; | ||||
public boolean crashed = false; | public boolean crashed = false; | ||||
} | } | ||||
@@ -0,0 +1,110 @@ | |||||
/* | |||||
* Copyright 2006 The Apache Software Foundation | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
* | |||||
*/ | |||||
package org.apache.tools.ant.taskdefs.optional.junit; | |||||
import java.io.IOException; | |||||
import java.io.OutputStream; | |||||
import org.apache.tools.ant.AntClassLoader; | |||||
import org.apache.tools.ant.types.Permissions; | |||||
/** | |||||
* Handles the portions of {@link JUnitTask} which need to directly access | |||||
* actual JUnit classes, so that junit.jar need not be on Ant's startup classpath. | |||||
* Neither JUnitTask.java nor JUnitTaskMirror.java nor their transitive static | |||||
* deps may import any junit.** classes! | |||||
* Specifically, need to not refer to | |||||
* - JUnitResultFormatter or its subclasses | |||||
* - JUnitVersionHelper | |||||
* - JUnitTestRunner | |||||
* Cf. {@link JUnitTask.SplitLoader#isSplit} | |||||
* Public only to permit access from classes in this package; do not use directly. | |||||
* | |||||
* @author refactoring tricks by Jesse Glick, real code by others | |||||
* @since 1.7 | |||||
* @see "bug #38799" | |||||
*/ | |||||
public interface JUnitTaskMirror { | |||||
void addVmExit(JUnitTest test, JUnitResultFormatterMirror formatter, | |||||
OutputStream out, final String message); | |||||
JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, boolean haltOnError, | |||||
boolean filterTrace, boolean haltOnFailure, boolean showOutput, | |||||
boolean logTestListenerEvents, AntClassLoader classLoader); | |||||
SummaryJUnitResultFormatterMirror newSummaryJUnitResultFormatter(); | |||||
public interface JUnitResultFormatterMirror { | |||||
void setOutput(OutputStream outputStream); | |||||
} | |||||
public interface SummaryJUnitResultFormatterMirror extends JUnitResultFormatterMirror { | |||||
void setWithOutAndErr(boolean value); | |||||
} | |||||
public interface JUnitTestRunnerMirror { | |||||
/** | |||||
* Used in formatter arguments as a placeholder for the basename | |||||
* of the output file (which gets replaced by a test specific | |||||
* output file name later). | |||||
* | |||||
* @since Ant 1.6.3 | |||||
*/ | |||||
String IGNORED_FILE_NAME = "IGNORETHIS"; | |||||
/** | |||||
* No problems with this test. | |||||
*/ | |||||
int SUCCESS = 0; | |||||
/** | |||||
* Some tests failed. | |||||
*/ | |||||
int FAILURES = 1; | |||||
/** | |||||
* An error occurred. | |||||
*/ | |||||
int ERRORS = 2; | |||||
void setPermissions(Permissions perm); | |||||
void run(); | |||||
void addFormatter(JUnitResultFormatterMirror formatter); | |||||
int getRetCode(); | |||||
void handleErrorFlush(String output); | |||||
void handleErrorOutput(String output); | |||||
void handleOutput(String output); | |||||
int handleInput(byte[] buffer, int offset, int length) throws IOException; | |||||
void handleFlush(String output); | |||||
} | |||||
} |
@@ -0,0 +1,72 @@ | |||||
/* | |||||
* Copyright 2006 The Apache Software Foundation | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||||
* you may not use this file except in compliance with the License. | |||||
* You may obtain a copy of the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, | |||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
* See the License for the specific language governing permissions and | |||||
* limitations under the License. | |||||
* | |||||
*/ | |||||
package org.apache.tools.ant.taskdefs.optional.junit; | |||||
import java.io.OutputStream; | |||||
import junit.framework.AssertionFailedError; | |||||
import junit.framework.Test; | |||||
import junit.framework.TestResult; | |||||
import org.apache.tools.ant.AntClassLoader; | |||||
/** | |||||
* Implementation of the part of the junit task which can directly refer to junit.* classes. | |||||
* Public only to permit use of reflection; do not use directly. | |||||
* @see JUnitTaskMirror | |||||
* @see "bug #38799" | |||||
* @since 1.7 | |||||
*/ | |||||
public final class JUnitTaskMirrorImpl implements JUnitTaskMirror { | |||||
private final JUnitTask task; | |||||
public JUnitTaskMirrorImpl(JUnitTask task) { | |||||
this.task = task; | |||||
} | |||||
public void addVmExit(JUnitTest test, JUnitResultFormatterMirror _formatter, | |||||
OutputStream out, final String message) { | |||||
JUnitResultFormatter formatter = (JUnitResultFormatter) _formatter; | |||||
formatter.setOutput(out); | |||||
formatter.startTestSuite(test); | |||||
//the trick to integrating test output to the formatter, is to | |||||
//create a special test class that asserts an error | |||||
//and tell the formatter that it raised. | |||||
Test t = new Test() { | |||||
public int countTestCases() { return 1; } | |||||
public void run(TestResult r) { | |||||
throw new AssertionFailedError(message); | |||||
} | |||||
}; | |||||
formatter.startTest(t); | |||||
formatter.addError(t, new AssertionFailedError(message)); | |||||
formatter.endTestSuite(test); | |||||
} | |||||
public JUnitTaskMirror.JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, | |||||
boolean haltOnError, boolean filterTrace, boolean haltOnFailure, | |||||
boolean showOutput, boolean logTestListenerEvents, AntClassLoader classLoader) { | |||||
return new JUnitTestRunner(test, haltOnError, filterTrace, haltOnFailure, | |||||
showOutput, logTestListenerEvents, classLoader); | |||||
} | |||||
public JUnitTaskMirror.SummaryJUnitResultFormatterMirror newSummaryJUnitResultFormatter() { | |||||
return new SummaryJUnitResultFormatter(); | |||||
} | |||||
} |
@@ -1,5 +1,5 @@ | |||||
/* | /* | ||||
* Copyright 2000-2005 The Apache Software Foundation | |||||
* Copyright 2000-2006 The Apache Software Foundation | |||||
* | * | ||||
* Licensed under the Apache License, Version 2.0 (the "License"); | * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
* you may not use this file except in compliance with the License. | * you may not use this file except in compliance with the License. | ||||
@@ -62,31 +62,7 @@ import org.apache.tools.ant.util.TeeOutputStream; | |||||
* @since Ant 1.2 | * @since Ant 1.2 | ||||
*/ | */ | ||||
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 occurred. | |||||
*/ | |||||
public static final int ERRORS = 2; | |||||
/** | |||||
* Used in formatter arguments as a placeholder for the basename | |||||
* of the output file (which gets replaced by a test specific | |||||
* output file name later). | |||||
* | |||||
* @since Ant 1.6.3 | |||||
*/ | |||||
public static final String IGNORED_FILE_NAME = "IGNORETHIS"; | |||||
public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestRunnerMirror { | |||||
/** | /** | ||||
* Holds the registered formatters. | * Holds the registered formatters. | ||||
@@ -441,7 +417,7 @@ public class JUnitTestRunner implements TestListener { | |||||
perm = permissions; | perm = permissions; | ||||
} | } | ||||
protected void handleOutput(String output) { | |||||
public void handleOutput(String output) { | |||||
if (!logTestListenerEvents && output.startsWith(JUnitTask.TESTLISTENER_PREFIX)) | if (!logTestListenerEvents && output.startsWith(JUnitTask.TESTLISTENER_PREFIX)) | ||||
; // ignore | ; // ignore | ||||
else if (systemOut != null) { | else if (systemOut != null) { | ||||
@@ -454,24 +430,24 @@ public class JUnitTestRunner implements TestListener { | |||||
* | * | ||||
* @since Ant 1.6 | * @since Ant 1.6 | ||||
*/ | */ | ||||
protected int handleInput(byte[] buffer, int offset, int length) | |||||
public int handleInput(byte[] buffer, int offset, int length) | |||||
throws IOException { | throws IOException { | ||||
return -1; | return -1; | ||||
} | } | ||||
protected void handleErrorOutput(String output) { | |||||
public void handleErrorOutput(String output) { | |||||
if (systemError != null) { | if (systemError != null) { | ||||
systemError.print(output); | systemError.print(output); | ||||
} | } | ||||
} | } | ||||
protected void handleFlush(String output) { | |||||
public void handleFlush(String output) { | |||||
if (systemOut != null) { | if (systemOut != null) { | ||||
systemOut.print(output); | systemOut.print(output); | ||||
} | } | ||||
} | } | ||||
protected void handleErrorFlush(String output) { | |||||
public void handleErrorFlush(String output) { | |||||
if (systemError != null) { | if (systemError != null) { | ||||
systemError.print(output); | systemError.print(output); | ||||
} | } | ||||
@@ -505,6 +481,10 @@ public class JUnitTestRunner implements TestListener { | |||||
formatters.addElement(f); | formatters.addElement(f); | ||||
} | } | ||||
public void addFormatter(JUnitTaskMirror.JUnitResultFormatterMirror f) { | |||||
formatters.addElement((JUnitResultFormatter) f); | |||||
} | |||||
/** | /** | ||||
* Entry point for standalone (forked) mode. | * Entry point for standalone (forked) mode. | ||||
* | * | ||||
@@ -645,7 +625,7 @@ public class JUnitTestRunner implements TestListener { | |||||
test.getOutfile() + fe.getExtension()); | test.getOutfile() + fe.getExtension()); | ||||
fe.setOutfile(destFile); | fe.setOutfile(destFile); | ||||
} | } | ||||
runner.addFormatter(fe.createFormatter()); | |||||
runner.addFormatter((JUnitResultFormatter) fe.createFormatter()); | |||||
} | } | ||||
} | } | ||||
@@ -29,7 +29,7 @@ import org.apache.tools.ant.BuildException; | |||||
* | * | ||||
*/ | */ | ||||
public class SummaryJUnitResultFormatter implements JUnitResultFormatter { | |||||
public class SummaryJUnitResultFormatter implements JUnitResultFormatter, JUnitTaskMirror.SummaryJUnitResultFormatterMirror { | |||||
/** | /** | ||||
* Formatter for timings. | * Formatter for timings. | ||||
@@ -1386,6 +1386,10 @@ mv /tmp/foo $ANT_HOME/bin/antRun | |||||
<code>org.apache.tools.ant.taskdefs.XSLTLiaison</code> | <code>org.apache.tools.ant.taskdefs.XSLTLiaison</code> | ||||
class.</p> | class.</p> | ||||
<p><em>As of Ant 1.7</em> <code><junit></code> no longer | |||||
requires you to have <code>junit.jar</code> in Ant's startup | |||||
classpath even if <code>ant-junit.jar</code> is present there.</p> | |||||
<p>Ant's class loader implementation uses Java's | <p>Ant's class loader implementation uses Java's | ||||
delegation model, see <a | delegation model, see <a | ||||
href="http://java.sun.com/products/jdk/1.2/docs/api/java/lang/ClassLoader.html">http://java.sun.com/products/jdk/1.2/docs/api/java/lang/ClassLoader.html</a> | href="http://java.sun.com/products/jdk/1.2/docs/api/java/lang/ClassLoader.html">http://java.sun.com/products/jdk/1.2/docs/api/java/lang/ClassLoader.html</a> | ||||
@@ -1776,4 +1780,4 @@ mv /tmp/foo $ANT_HOME/bin/antRun | |||||
</faq> | </faq> | ||||
</faqsection> | </faqsection> | ||||
</document> | |||||
</document> |