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> | |||||