You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by jg...@apache.org on 2010/02/05 03:51:41 UTC
svn commit: r906782 - in /ant/core/branches/run-single-test-method:
docs/manual/OptionalTasks/ lib/optional/
src/main/org/apache/tools/ant/taskdefs/optional/junit/
src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/
Author: jglick
Date: Fri Feb 5 02:51:40 2010
New Revision: 906782
URL: http://svn.apache.org/viewvc?rev=906782&view=rev
Log:
Attempting to forward-port patch made against 1.7.1.
Added:
ant/core/branches/run-single-test-method/lib/optional/junit-4.8.1.jar (with props)
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java (with props)
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultParser.java (with props)
ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/BatchTestTest.java (with props)
Removed:
ant/core/branches/run-single-test-method/lib/optional/junit-3.8.2.jar
Modified:
ant/core/branches/run-single-test-method/docs/manual/OptionalTasks/junit.html
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/ (props changed)
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java
ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java
Modified: ant/core/branches/run-single-test-method/docs/manual/OptionalTasks/junit.html
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/docs/manual/OptionalTasks/junit.html?rev=906782&r1=906781&r2=906782&view=diff
==============================================================================
--- ant/core/branches/run-single-test-method/docs/manual/OptionalTasks/junit.html (original)
+++ ant/core/branches/run-single-test-method/docs/manual/OptionalTasks/junit.html Fri Feb 5 02:51:40 2010
@@ -351,7 +351,7 @@
<p><em>since Ant 1.6.</em></p>
-<h4>formatter</h4>
+<h4><a name="formatter">formatter</a></h4>
<p>The results of the tests can be printed in different
formats. Output will always be sent to a file, unless you set the
@@ -440,6 +440,26 @@
<td align="center">Yes</td>
</tr>
<tr>
+ <td valign="top">methods</td>
+ <td valign="top">Comma-separated list of names of test case methods to execute.
+ <em>Since Ant 1.7.1</em>
+ <p>The <code>methods</code> attribute can be useful in the following scenarios:</p>
+ <ul>
+ <li>A test method has failed and you want to re-run the test method
+ to test a fix or re-run the test under the Java debugger without
+ having to wait for the other (possibly long running) test methods
+ to complete.</li>
+ <li>One or more test methods are running slower than expected and you
+ want to re-run them under a Java profiler (without the overhead
+ of running the profiler whilst other test methods are being
+ executed).</li>
+ </ul>
+ <p>If the <code>methods</code> attribute is used but no test method
+ is specified, then no test method from the suite will be executed.</p>
+ </td>
+ <td align="center">No; default is to run all test methods in the suite.</td>
+ </tr>
+ <tr>
<td valign="top">fork</td>
<td valign="top">Run the tests in a separate VM.
Overrides value set in <code><junit></code>.</td>
@@ -570,6 +590,17 @@
<td align="center" valign="top">No; default is the current directory.</td>
</tr>
<tr>
+ <td valign="top">rerunfailed</td>
+ <td valign="top">Run only those test methods that failed during the previous
+ execution. <em>Since Ant 1.7.1</em>
+ <p>Results of the previous execution are taken from XML report files
+ generated by the XML <a href="#formatter">formatter</a>.<br />
+ The report files are searched for in the target directory for reports,
+ i.e. in the directory specified by the <code>todir</code> attribute.</p>
+ </td>
+ <td align="center" valign="top">No; default is <code>off</code>.</td>
+ </tr>
+ <tr>
<td valign="top">if</td>
<td valign="top">Only run tests <a href="../properties.html#if+unless">if the named property is set</a>.</td>
<td align="center" valign="top">No</td>
Added: ant/core/branches/run-single-test-method/lib/optional/junit-4.8.1.jar
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/lib/optional/junit-4.8.1.jar?rev=906782&view=auto
==============================================================================
Binary file - no diff available.
Propchange: ant/core/branches/run-single-test-method/lib/optional/junit-4.8.1.jar
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Propchange: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Feb 5 02:51:40 2010
@@ -0,0 +1,4 @@
+JUnitTask.java.orig
+BatchTest.java.orig
+JUnitTestRunner.java.orig
+JUnitTest.java.orig
Modified: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java?rev=906782&r1=906781&r2=906782&view=diff
==============================================================================
--- ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java (original)
+++ ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java Fri Feb 5 02:51:40 2010
@@ -19,15 +19,23 @@
package org.apache.tools.ant.taskdefs.optional.junit;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
+import java.util.List;
import java.util.Vector;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.resources.Resources;
+import org.xml.sax.SAXException;
/**
* <p> Create then run <code>JUnitTest</code>'s based on the list of files
@@ -48,6 +56,9 @@
/** the list of filesets containing the testcase filename rules */
private Resources resources = new Resources();
+ /** only run tests that failed during the previous run */
+ private boolean failedOnly = false;
+
/**
* create a new batchtest instance
* @param project the project it depends on.
@@ -58,6 +69,18 @@
}
/**
+ * Sets a flag that only tests that failed during the previous session
+ * should be executed.
+ * The results of the previous test execution are taken from XML report
+ * files so an XML report file with output to file should be used
+ * when this option is used.
+ * @since Ant 1.7.1
+ */
+ public void setRerunfailed(boolean rerunFailed) {
+ this.failedOnly = rerunFailed;
+ }
+
+ /**
* Add a new fileset instance to this batchtest. Whatever the fileset is,
* only filename that are <tt>.java</tt> or <tt>.class</tt> will be
* considered as 'candidates'.
@@ -124,15 +147,203 @@
*/
private JUnitTest[] createAllJUnitTest() {
String[] filenames = getFilenames();
- JUnitTest[] tests = new JUnitTest[filenames.length];
- for (int i = 0; i < tests.length; i++) {
- String classname = javaToClass(filenames[i]);
- tests[i] = createJUnitTest(classname);
+ JUnitTest[] tests;
+ if (!failedOnly) {
+ tests = new JUnitTest[filenames.length];
+ for (int i = 0; i < tests.length; i++) {
+ String classname = javaToClass(filenames[i]);
+ tests[i] = createJUnitTest(classname);
+ }
+ } else {
+ List testsList = new ArrayList(10);
+ for (int i = 0; i < filenames.length; i++) {
+ String classname = javaToClass(filenames[i]);
+ File resultsFile = getXMLResultsFile(classname);
+ if (resultsFile == null) {
+ continue;
+ }
+ List testListLines = parseResultsFile(resultsFile);
+ if ((testListLines != null) && !testListLines.isEmpty()) {
+ final int count = testListLines.size();
+ for (int j = 0; j < count; j++) {
+ String line = (String) testListLines.get(j);
+ JUnitTest test;
+ try {
+ test = parseTestListLine(line); //may return null
+ } catch (IllegalArgumentException ex) {
+ project.log(
+ "File " + resultsFile
+ + " contained invalid description of tests: "
+ + ex.getMessage(),
+ Project.MSG_WARN);
+ break;
+ }
+ if (test != null) {
+ testsList.add(test);
+ }
+ }
+ }
+ }
+ if (!testsList.isEmpty()) {
+ tests = (JUnitTest[])
+ testsList.toArray(new JUnitTest[testsList.size()]);
+ } else {
+ tests = new JUnitTest[0];
+ }
}
return tests;
}
/**
+ * Finds an XML report file for the given class name.
+ * @param testClassName name of a test class for which a result file should
+ * be found
+ * @return XML report file for the given class name,
+ * or <code>null</code> if the report file does not exist
+ * or if it is not a plain file
+ */
+ private File getXMLResultsFile(String testClassName) {
+ File file = new File(getTodir(), "TEST-" + testClassName + ".xml");
+ if (!file.isFile()) {
+ project.log("XML results file " + file + " does not exist",
+ Project.MSG_VERBOSE);
+ return null;
+ }
+ return file;
+ }
+
+ /**
+ * Parses the given XML report file.
+ * @param file XML report file to be parsed
+ * @return list of test specification lines,
+ * or <code>null</code> if the file does not exist
+ * or if some error occured while reading it or during parsing
+ */
+ private List parseResultsFile(File file) {
+ if (!file.canRead()) {
+ project.log("Cannot read XML results file " + file,
+ Project.MSG_WARN);
+ return null;
+ }
+ project.log("Parsing file " + file, Project.MSG_VERBOSE);
+
+ Reader reader = null;
+ try {
+ reader = new BufferedReader(
+ new InputStreamReader(new FileInputStream(file), "UTF8"));
+ return XMLResultParser.parseResultsFile(reader);
+ } catch (IOException ex1) {
+ project.log("Error while reading XML results file " + file,
+ ex1,
+ Project.MSG_ERR);
+ return null;
+ } catch (SAXException ex2) {
+ project.log("Error while parsing XML results file " + file,
+ ex2,
+ Project.MSG_ERR);
+ return null;
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ } catch (IOException ex) {
+ //give up
+ }
+ }
+ }
+ }
+
+ /**
+ * Parses one line of a test list file and creates <code>JUnitTest</code>
+ * instances for the tests corresponding to the specification on the line.
+ * @param line string describing a test
+ * @return <code>JUnitTest</code> that would execute test methods that are
+ * specified by the given line;
+ * or <code>null</code> if an empty test would be created
+ * @exception java.lang.IllegalArgumentException
+ * if the line is malformed
+ */
+ private JUnitTest parseTestListLine(String line)
+ throws IllegalArgumentException {
+ String className;
+ String methodsList;
+ int colonIndex = line.indexOf(':');
+ if (colonIndex == -1) {
+ // no specification of test methods
+ className = line.trim();
+ methodsList = null;
+ } else {
+ className = line.substring(0, colonIndex).trim();
+ methodsList = line.substring(colonIndex + 1);
+ }
+
+ checkClassNameIsValid(className);
+ if ("junit.framework.JUnit4TestCaseFacade".equals(className)) {
+ // This is an artificial test case failure.
+ // It is used e.g. to report that a test class did not have any
+ // test methods.
+ return null;
+ }
+
+ if (methodsList == null) {
+ return createJUnitTest(className);
+ } else {
+ String[] methods = JUnitTest.parseTestMethodNamesList(methodsList);
+ return (methods.length != 0) ? createJUnitTest(className, methods)
+ : null;
+ }
+ }
+
+ /**
+ * Checks whether the passed string is a valid class name.
+ * @param className class name to be checked
+ * @throws java.lang.IllegalArgumentException
+ * if the name is not a valid class name
+ */
+ private void checkClassNameIsValid(String className) throws IllegalArgumentException {
+ final String errMsg = "Invalid class name";
+ int dotIndex = className.indexOf('.');
+ if (dotIndex == -1) {
+ checkJavaIdentifier(className, errMsg);
+ } else {
+ int previousDotIndex = -1;
+ do {
+ checkJavaIdentifier(className.substring(previousDotIndex + 1, dotIndex),
+ errMsg);
+ previousDotIndex = dotIndex;
+ dotIndex = className.indexOf('.', previousDotIndex + 1);
+ } while (dotIndex != -1);
+ checkJavaIdentifier(className.substring(previousDotIndex + 1),
+ errMsg);
+ }
+ }
+
+ /**
+ * Checks whether the passed string is a valid Java identifier.
+ * @param name name to be checked
+ * @param errMsg message to used in the thrown exception if the name
+ * is found invalid
+ * @throws java.lang.IllegalArgumentException
+ * if the name is not a valid Java identifier
+ */
+ private static void checkJavaIdentifier(String name,
+ String errMsg)
+ throws IllegalArgumentException {
+ int length = name.length();
+ if ((length == 0) || !Character.isJavaIdentifierStart(name.charAt(0))) {
+ throw new IllegalArgumentException(errMsg + ": " + name);
+ }
+ if (length > 1) {
+ final char[] chars = name.substring(1).toCharArray();
+ for (int i = 0; i < chars.length; i++) {
+ if (!Character.isJavaIdentifierPart(chars[i])) {
+ throw new IllegalArgumentException(errMsg + ": " + name);
+ }
+ }
+ }
+ }
+
+ /**
* Iterate over all filesets and return the filename of all files
* that end with <tt>.java</tt> or <tt>.class</tt>. This is to avoid
* wrapping a <tt>JUnitTest</tt> over an xml file for example. A Testcase
@@ -182,8 +393,23 @@
* @return the <tt>JUnitTest</tt> over the given classname.
*/
private JUnitTest createJUnitTest(String classname) {
+ return createJUnitTest(classname, null);
+ }
+
+ /**
+ * Create a <tt>JUnitTest</tt> that has the same property as this
+ * <tt>BatchTest</tt> instance.
+ * @param classname the name of the class that should be run as a
+ * <tt>JUnitTest</tt>. It must be a fully qualified name.
+ * @param methods array of names of test methods within the class
+ * to be executed, or <code>null</code> if all test methods
+ * in the test suite given by the class should be executed
+ * @return the <tt>JUnitTest</tt> over the given classname and test methods.
+ */
+ private JUnitTest createJUnitTest(String classname, String[] methods) {
JUnitTest test = new JUnitTest();
test.setName(classname);
+ test.setMethods(methods);
test.setHaltonerror(this.haltOnError);
test.setHaltonfailure(this.haltOnFail);
test.setFiltertrace(this.filtertrace);
Modified: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java?rev=906782&r1=906781&r2=906782&view=diff
==============================================================================
--- ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java (original)
+++ ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java Fri Feb 5 02:51:40 2010
@@ -23,6 +23,7 @@
*/
public class Constants {
+ static final String METHOD_NAMES = "methods=";
static final String HALT_ON_ERROR = "haltOnError=";
static final String HALT_ON_FAILURE = "haltOnFailure=";
static final String FILTERTRACE = "filtertrace=";
Added: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java?rev=906782&view=auto
==============================================================================
--- ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java (added)
+++ ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java Fri Feb 5 02:51:40 2010
@@ -0,0 +1,250 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 2008 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.util.Iterator;
+import java.util.List;
+import junit.framework.JUnit4TestAdapterCache;
+import junit.framework.Test;
+import junit.framework.TestResult;
+import org.junit.runner.Description;
+import org.junit.runner.Request;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.runner.notification.RunNotifier;
+
+/**
+ * Adapter between JUnit 3.8.x API and JUnit 4.x API for execution of tests
+ * and listening of events (test start, test finish, test failure).
+ * The constructor is passed a JUnit 4 test class and a list of name of methods
+ * in it that should be executed. Method {@link #run run(TestResult)} executes
+ * the given JUnit-4-style test methods and notifies the given {@code TestResult}
+ * object using its old (JUnit 3.8.x style) API.
+ *
+ * @author Marian Petras
+ */
+public class JUnit4TestMethodAdapter implements Test {
+
+ private final Class testClass;
+ private final String[] methodNames;
+ private final Runner runner;
+ private final Cache cache;
+
+ /**
+ * Creates a new adapter for the given class and a method within the class.
+ *
+ * @param testClass test class containing the method to be executed
+ * @param methodNames names of the test methods that are to be executed
+ * @exception java.lang.IllegalArgumentException
+ * if any of the arguments is {@code null}
+ * or if any of the given method names is {@code null} or empty
+ */
+ public JUnit4TestMethodAdapter(final Class testClass,
+ final String[] methodNames) {
+ if (testClass == null) {
+ throw new IllegalArgumentException("testClass is <null>");
+ }
+ if (methodNames == null) {
+ throw new IllegalArgumentException("methodNames is <null>");
+ }
+ for (int i = 0; i < methodNames.length; i++) {
+ if (methodNames[i] == null) {
+ throw new IllegalArgumentException("method name #" + i + " is <null>");
+ }
+ if (methodNames[i].length() == 0) {
+ throw new IllegalArgumentException("method name #" + i + " is empty");
+ }
+ }
+ this.testClass = testClass;
+ this.methodNames = methodNames;
+ this.cache = Cache.instance;
+
+ // Warning: If 'testClass' is an old-style (pre-JUnit-4) class,
+ // then all its test methods will be executed by the returned runner!
+ Request request;
+ if (methodNames.length == 1) {
+ request = Request.method(testClass, methodNames[0]);
+ } else {
+ request = Request.aClass(testClass).filterWith(
+ new MultipleMethodsFilter(testClass, methodNames));
+ }
+ runner = request.getRunner();
+ }
+
+ public int countTestCases() {
+ return runner.testCount();
+ }
+
+ public Description getDescription() {
+ return runner.getDescription();
+ }
+
+ public List/*<Test>*/ getTests() {
+ return cache.asTestList(getDescription());
+ }
+
+ public Class getTestClass() {
+ return testClass;
+ }
+
+ public void run(final TestResult result) {
+ runner.run(cache.getNotifier(result));
+ }
+
+ public String toString() {
+ String testClassName = testClass.getName();
+ StringBuilder buf = new StringBuilder(testClassName.length()
+ + 12 * methodNames.length)
+ .append(':');
+ if (methodNames.length != 0) {
+ buf.append(methodNames[0]);
+ for (int i = 1; i < methodNames.length; i++) {
+ buf.append(',')
+ .append(methodNames[i]);
+ }
+ }
+ return buf.toString();
+ }
+
+ private static final class MultipleMethodsFilter extends Filter {
+
+ private final Description methodsListDescription;
+ private final Class testClass;
+ private final String[] methodNames;
+
+ private MultipleMethodsFilter(Class testClass, String[] methodNames) {
+ if (testClass == null) {
+ throw new IllegalArgumentException("testClass is <null>");
+ }
+ if (methodNames == null) {
+ throw new IllegalArgumentException("methodNames is <null>");
+ }
+ methodsListDescription = Description.createSuiteDescription(testClass);
+ for (int i = 0; i < methodNames.length; i++) {
+ methodsListDescription.addChild(
+ Description.createTestDescription(testClass, methodNames[i]));
+ }
+ this.testClass = testClass;
+ this.methodNames = methodNames;
+ }
+
+ public boolean shouldRun(Description description) {
+ if (methodNames.length == 0) {
+ return false;
+ }
+ if (description.isTest()) {
+ Iterator/*<Description>*/ it = methodsListDescription.getChildren().iterator();
+ while (it.hasNext()) {
+ Description methodDescription = (Description) it.next();
+ if (methodDescription.equals(description)) {
+ return true;
+ }
+ }
+ } else {
+ Iterator/*<Description>*/ it = description.getChildren().iterator();
+ while (it.hasNext()) {
+ Description each = (Description) it.next();
+ if (shouldRun(each)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public String describe() {
+ StringBuilder buf = new StringBuilder(40);
+ if (methodNames.length == 0) {
+ buf.append("No methods");
+ } else {
+ buf.append(methodNames.length == 1 ? "Method" : "Methods");
+ buf.append(' ');
+ buf.append(methodNames[0]);
+ for (int i = 1; i < methodNames.length; i++) {
+ buf.append(',').append(methodNames[i]);
+ }
+ }
+ buf.append('(').append(testClass.getName()).append(')');
+ return buf.toString();
+ }
+
+ }
+
+ /**
+ * Effectively a copy of {@code JUnit4TestAdapterCache}, except that its
+ * method {@code getNotifier()} does not require an argument
+ * of type {@code JUnit4TestAdapter}.
+ */
+ private static final class Cache extends JUnit4TestAdapterCache {
+
+ private static final Cache instance = new Cache();
+
+ public static JUnit4TestAdapterCache getDefault() {
+ return instance;
+ }
+
+ public RunNotifier getNotifier(final TestResult result) {
+ RunNotifier notifier = new RunNotifier();
+ notifier.addListener(new RunListener() {
+ public void testFailure(Failure failure) throws Exception {
+ result.addError(asTest(failure.getDescription()),
+ failure.getException());
+ }
+
+ public void testFinished(Description description)
+ throws Exception {
+ result.endTest(asTest(description));
+ }
+
+ public void testStarted(Description description)
+ throws Exception {
+ result.startTest(asTest(description));
+ }
+ });
+ return notifier;
+ }
+
+ }
+
+}
\ No newline at end of file
Propchange: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java?rev=906782&r1=906781&r2=906782&view=diff
==============================================================================
--- ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java (original)
+++ ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java Fri Feb 5 02:51:40 2010
@@ -729,6 +729,7 @@
new SplitClassLoader(myLoader, path, getProject(),
new String[] {
"BriefJUnitResultFormatter",
+ "JUnit4TestMethodAdapter",
"JUnitResultFormatter",
"JUnitTaskMirrorImpl",
"JUnitTestRunner",
@@ -752,6 +753,8 @@
* @since Ant 1.2
*/
public void execute() throws BuildException {
+ checkMethodLists();
+
setupJUnitDelegate();
List testLists = new ArrayList();
@@ -836,6 +839,9 @@
while (iter.hasNext()) {
test = (JUnitTest) iter.next();
printDual(writer, logWriter, test.getName());
+ if (test.getMethods() != null) {
+ printDual(writer, logWriter, ":" + test.getMethodsString().replace(',', '+'));
+ }
if (test.getTodir() == null) {
printDual(writer, logWriter,
"," + getProject().resolveFile("."));
@@ -907,6 +913,9 @@
cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
if (casesFile == null) {
cmd.createArgument().setValue(test.getName());
+ if (test.getMethods() != null) {
+ cmd.createArgument().setValue(Constants.METHOD_NAMES + test.getMethodsString());
+ }
} else {
log("Running multiple tests in the same VM", Project.MSG_VERBOSE);
cmd.createArgument().setValue(Constants.TESTSFILE + casesFile);
@@ -1307,7 +1316,7 @@
if (classLoader != null) {
classLoader.setThreadContextLoader();
}
- runner = delegate.newJUnitTestRunner(test, test.getHaltonerror(),
+ runner = delegate.newJUnitTestRunner(test, test.getMethods(), test.getHaltonerror(),
test.getFiltertrace(),
test.getHaltonfailure(), false,
true, classLoader);
@@ -1393,6 +1402,29 @@
}
/**
+ * Verifies all <code>test</code> elements having the <code>methods</code>
+ * attribute specified and having the <code>if</code>-condition resolved
+ * to true, that the value of the <code>methods</code> attribute is valid.
+ * @exception BuildException if some of the tests matching the described
+ * conditions has invalid value of the
+ * <code>methods</code> attribute
+ * @since Ant 1.7.1
+ */
+ private void checkMethodLists() throws BuildException {
+ if (tests.isEmpty()) {
+ return;
+ }
+
+ Enumeration testsEnum = tests.elements();
+ while (testsEnum.hasMoreElements()) {
+ JUnitTest test = (JUnitTest) testsEnum.nextElement();
+ if (test.hasMethodsSpecified() && test.shouldRun(getProject())) {
+ test.resolveMethods();
+ }
+ }
+ }
+
+ /**
* return an enumeration listing each test, then each batchtest
* @return enumeration
* @since Ant 1.3
Modified: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java?rev=906782&r1=906781&r2=906782&view=diff
==============================================================================
--- ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java (original)
+++ ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java Fri Feb 5 02:51:40 2010
@@ -55,6 +55,7 @@
/**
* Create a new test runner for a test.
* @param test the test to run.
+ * @param methods names of the test methods to be run.
* @param haltOnError if true halt the tests if an error occurs.
* @param filterTrace if true filter the stack traces.
* @param haltOnFailure if true halt the test if a failure occurs.
@@ -63,7 +64,7 @@
* @param classLoader the classloader to use to create the runner.
* @return the test runner.
*/
- JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, boolean haltOnError,
+ JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError,
boolean filterTrace, boolean haltOnFailure, boolean showOutput,
boolean logTestListenerEvents, AntClassLoader classLoader);
Modified: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java?rev=906782&r1=906781&r2=906782&view=diff
==============================================================================
--- ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java (original)
+++ ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java Fri Feb 5 02:51:40 2010
@@ -60,9 +60,10 @@
/** {@inheritDoc}. */
public JUnitTaskMirror.JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test,
+ String[] methods,
boolean haltOnError, boolean filterTrace, boolean haltOnFailure,
boolean showOutput, boolean logTestListenerEvents, AntClassLoader classLoader) {
- return new JUnitTestRunner(test, haltOnError, filterTrace, haltOnFailure,
+ return new JUnitTestRunner(test, methods, haltOnError, filterTrace, haltOnFailure,
showOutput, logTestListenerEvents, classLoader);
}
Modified: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java?rev=906782&r1=906781&r2=906782&view=diff
==============================================================================
--- ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java (original)
+++ ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java Fri Feb 5 02:51:40 2010
@@ -22,6 +22,7 @@
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;
+import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyHelper;
@@ -41,6 +42,19 @@
/** the name of the test case */
private String name = null;
+ /**
+ * whether the list of test methods has been specified
+ * @see #setMethods(java.lang.String)
+ * @see #setMethods(java.lang.String[])
+ */
+ private boolean methodsSpecified = false;
+
+ /** comma-separated list of names of test methods to execute */
+ private String methodsList = null;
+
+ /** the names of test methods to execute */
+ private String[] methods = null;
+
/** the name of the result file */
private String outfile = null;
@@ -73,11 +87,53 @@
* @param filtertrace if true filter stack traces.
*/
public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure,
- boolean filtertrace) {
+ boolean filtertrace) {
+ this(name, haltOnError, haltOnFailure, filtertrace, null);
+ }
+
+ /**
+ * Constructor with options.
+ * @param name the name of the test.
+ * @param haltOnError if true halt the tests if there is an error.
+ * @param haltOnFailure if true halt the tests if there is a failure.
+ * @param filtertrace if true filter stack traces.
+ * @param methods if true run only test methods that failed during the
+ * previous run of the test suite
+ * @since Ant 1.7.1
+ */
+ public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure,
+ boolean filtertrace, String[] methods) {
this.name = name;
this.haltOnError = haltOnError;
this.haltOnFail = haltOnFailure;
this.filtertrace = filtertrace;
+ this.methods = methods;
+ this.methodsSpecified = (methods != null);
+ }
+
+ /**
+ * Sets names of individual test methods to be executed.
+ * @param value comma-separated list of names of individual test methods
+ * to be executed,
+ * or <code>null</code> if all test methods should be executed
+ * @since Ant 1.7.1
+ */
+ public void setMethods(String value) {
+ methodsList = value;
+ methodsSpecified = (value != null);
+ methods = null;
+ }
+
+ /**
+ * Sets names of individual test methods to be executed.
+ * @param value non-empty array of names of test methods to be executed
+ * @see #setMethods(String)
+ * @since Ant 1.7.1
+ */
+ void setMethods(String[] value) {
+ methods = value;
+ methodsSpecified = (value != null);
+ methodsList = null;
}
/**
@@ -97,6 +153,189 @@
}
/**
+ * Informs whether a list of test methods has been specified in this test.
+ * @return <code>true</code> if test methods to be executed have been
+ * specified, <code>false</code> otherwise
+ * @see #setMethods(java.lang.String)
+ * @see #setMethods(java.lang.String[])
+ * @since Ant 1.7.1
+ */
+ boolean hasMethodsSpecified() {
+ return methodsSpecified;
+ }
+
+ /**
+ * Get names of individual test methods to be executed.
+ *
+ * @return array of names of the individual test methods to be executed,
+ * or <code>null</code> if all test methods in the suite
+ * defined by the test class will be executed
+ * @since Ant 1.7.1
+ */
+ String[] getMethods() {
+ if (methodsSpecified && (methods == null)) {
+ resolveMethods();
+ }
+ return methods;
+ }
+
+ /**
+ * Gets a comma-separated list of names of methods that are to be executed
+ * by this test.
+ * @return the comma-separated list of test method names, or an empty
+ * string of no method is to be executed, or <code>null</code>
+ * if no method is specified
+ * @since Ant 1.7.1
+ */
+ String getMethodsString() {
+ if ((methodsList == null) && methodsSpecified) {
+ if (methods.length == 0) {
+ methodsList = "";
+ } else if (methods.length == 1) {
+ methodsList = methods[0];
+ } else {
+ StringBuffer buf = new StringBuffer(methods.length * 16);
+ buf.append(methods[0]);
+ for (int i = 1; i < methods.length; i++) {
+ buf.append(',').append(methods[i]);
+ }
+ methodsList = buf.toString();
+ }
+ }
+ return methodsList;
+ }
+
+ /**
+ * Computes the value of the {@link #methods} field from the value
+ * of the {@link #methodsList} field, if it has not been computed yet.
+ * @exception BuildException if the value of the {@link #methodsList} field
+ * was invalid
+ * @since Ant 1.7.1
+ */
+ void resolveMethods() {
+ if ((methods == null) && methodsSpecified) {
+ try {
+ methods = parseTestMethodNamesList(methodsList);
+ } catch (IllegalArgumentException ex) {
+ throw new BuildException(
+ "Invalid specification of test methods: \""
+ + methodsList
+ + "\"; expected: comma-separated list of valid Java identifiers",
+ ex);
+ }
+ }
+ }
+
+ /**
+ * Parses a comma-separated list of method names and check their validity.
+ * @param methodNames comma-separated list of method names to be parsed
+ * @return array of individual test method names
+ * @exception java.lang.IllegalArgumentException
+ * if the given string is <code>null</code> or if it is not
+ * a comma-separated list of valid Java identifiers;
+ * an empty string is acceptable and is handled as an empty
+ * list
+ * @since Ant 1.7.1
+ */
+ static String[] parseTestMethodNamesList(String methodNames)
+ throws IllegalArgumentException {
+ if (methodNames == null) {
+ throw new IllegalArgumentException("methodNames is <null>");
+ }
+
+ methodNames = methodNames.trim();
+
+ int length = methodNames.length();
+ if (length == 0) {
+ return new String[0];
+ }
+
+ /* strip the trailing comma, if any */
+ if (methodNames.charAt(length - 1) == ',') {
+ methodNames = methodNames.substring(0, length - 1).trim();
+ length = methodNames.length();
+ if (length == 0) {
+ throw new IllegalArgumentException("Empty method name");
+ }
+ }
+
+ final char[] chars = methodNames.toCharArray();
+ /* easy detection of one particular case of illegal string: */
+ if (chars[0] == ',') {
+ throw new IllegalArgumentException("Empty method name");
+ }
+ /* count number of method names: */
+ int wordCount = 1;
+ for (int i = 1; i < chars.length; i++) {
+ if (chars[i] == ',') {
+ wordCount++;
+ }
+ }
+ /* prepare the resulting array: */
+ String[] result = new String[wordCount];
+ /* parse the string: */
+ final int stateBeforeWord = 1;
+ final int stateInsideWord = 2;
+ final int stateAfterWord = 3;
+ //
+ int state = stateBeforeWord;
+ int wordStartIndex = -1;
+ int wordIndex = 0;
+ for (int i = 0; i < chars.length; i++) {
+ char c = chars[i];
+ switch (state) {
+ case stateBeforeWord:
+ if (c == ',') {
+ throw new IllegalArgumentException("Empty method name");
+ } else if (c == ' ') {
+ // remain in the same state
+ } else if (Character.isJavaIdentifierStart(c)) {
+ wordStartIndex = i;
+ state = stateInsideWord;
+ } else {
+ throw new IllegalArgumentException("Illegal start of method name: " + c);
+ }
+ break;
+ case stateInsideWord:
+ if (c == ',') {
+ result[wordIndex++] = new String(methodNames.substring(wordStartIndex, i));
+ state = stateBeforeWord;
+ } else if (c == ' ') {
+ result[wordIndex++] = new String(methodNames.substring(wordStartIndex, i));
+ state = stateAfterWord;
+ } else if (Character.isJavaIdentifierPart(c)) {
+ // remain in the same state
+ } else {
+ throw new IllegalArgumentException("Illegal character in method name: " + c);
+ }
+ break;
+ case stateAfterWord:
+ if (c == ',') {
+ state = stateBeforeWord;
+ } else if (c == ' ') {
+ // remain in the same state
+ } else {
+ throw new IllegalArgumentException("Space in method name");
+ }
+ break;
+ default:
+ // this should never happen
+ }
+ }
+ switch (state) {
+ case stateBeforeWord:
+ case stateAfterWord:
+ break;
+ case stateInsideWord:
+ result[wordIndex++] = new String(methodNames.substring(wordStartIndex, chars.length));
+ break;
+ default:
+ // this should never happen
+ }
+ return result;
+ }
+
+ /**
* Get the name of the test class.
* @return the name of the test.
*/
Modified: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java?rev=906782&r1=906781&r2=906782&view=diff
==============================================================================
--- ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java (original)
+++ ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java Fri Feb 5 02:51:40 2010
@@ -163,6 +163,9 @@
*/
private static String crashFile = null;
+ /** Names of test methods to execute */
+ private String[] methods = null;
+
/**
* Constructor for fork=true or when the user hasn't specified a
* classpath.
@@ -205,7 +208,26 @@
public JUnitTestRunner(JUnitTest test, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure,
boolean showOutput, boolean logTestListenerEvents) {
- this(test, haltOnError, filtertrace, haltOnFailure, showOutput,
+ this(test, null, haltOnError, filtertrace, haltOnFailure, showOutput,
+ logTestListenerEvents, null);
+ }
+
+ /**
+ * Constructor for fork=true or when the user hasn't specified a
+ * classpath.
+ * @param test the test to run.
+ * @param methods names of methods of the test to be executed.
+ * @param haltOnError whether to stop the run if an error is found.
+ * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+ * @param haltOnFailure whether to stop the run if failure is found.
+ * @param showOutput whether to send output to System.out/.err as well as formatters.
+ * @param logTestListenerEvents whether to print TestListener events.
+ * @since Ant 1.7
+ */
+ public JUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError,
+ boolean filtertrace, boolean haltOnFailure,
+ boolean showOutput, boolean logTestListenerEvents) {
+ this(test, methods, haltOnError, filtertrace, haltOnFailure, showOutput,
logTestListenerEvents, null);
}
@@ -254,12 +276,26 @@
boolean filtertrace, boolean haltOnFailure,
boolean showOutput, boolean logTestListenerEvents,
ClassLoader loader) {
+ this(test, null, haltOnError, filtertrace, haltOnFailure, showOutput,
+ logTestListenerEvents, loader);
+ }
+
+
+ /**
+ * Constructor to use when the user has specified a classpath.
+ * @since Ant 1.7
+ */
+ public JUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError,
+ boolean filtertrace, boolean haltOnFailure,
+ boolean showOutput, boolean logTestListenerEvents,
+ ClassLoader loader) {
JUnitTestRunner.filtertrace = filtertrace;
this.junitTest = test;
this.haltOnError = haltOnError;
this.haltOnFailure = haltOnFailure;
this.showOutput = showOutput;
this.logTestListenerEvents = logTestListenerEvents;
+ this.methods = methods;
this.loader = loader;
}
@@ -340,9 +376,12 @@
loader);
}
+ final boolean testMethodsSpecified = (methods != null);
+
// check for a static suite method first, even when using
// JUnit 4
Method suiteMethod = null;
+ if (!testMethodsSpecified) {
try {
// check if there is a suite method
suiteMethod = testClass.getMethod("suite", new Class[0]);
@@ -350,6 +389,7 @@
// no appropriate suite method found. We don't report any
// error here since it might be perfectly normal.
}
+ }
if (suiteMethod != null) {
// if there is a suite method available, then try
@@ -359,7 +399,23 @@
} else {
Class junit4TestAdapterClass = null;
+ boolean useSingleMethodAdapter = false;
+ if (junit.framework.TestCase.class.isAssignableFrom(testClass)) {
+ // Do not use JUnit 4 API for running JUnit 3.x
+ // tests - it is not able to run individual test
+ // methods.
+ //
+ // Technical details:
+ // org.junit.runner.Request.method(Class, String).getRunner()
+ // would return a runner which always executes all
+ // test methods. The reason is that the Runner would be
+ // an instance of class
+ // org.junit.internal.runners.OldTestClassRunner
+ // that does not implement interface Filterable - so it
+ // is unable to filter out test methods not matching
+ // the requested name.
+ } else {
// Check for JDK 5 first. Will *not* help on JDK 1.4
// if only junit-4.0.jar in CP because in that case
// linkage of whole task will already have failed! But
@@ -373,10 +429,29 @@
if (loader == null) {
junit4TestAdapterClass =
Class.forName(JUNIT_4_TEST_ADAPTER);
+ if (testMethodsSpecified) {
+ /*
+ * We cannot try to load the JUnit4TestAdapter
+ * before trying to load JUnit4TestMethodAdapter
+ * because it might fail with
+ * NoClassDefFoundException, instead of plain
+ * ClassNotFoundException.
+ */
+ junit4TestAdapterClass = Class.forName(
+ "org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter");
+ useSingleMethodAdapter = true;
+ }
} else {
junit4TestAdapterClass =
Class.forName(JUNIT_4_TEST_ADAPTER,
true, loader);
+ if (testMethodsSpecified) {
+ junit4TestAdapterClass =
+ Class.forName(
+ "org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter",
+ true, loader);
+ useSingleMethodAdapter = true;
+ }
}
} catch (ClassNotFoundException e) {
// OK, fall back to JUnit 3.
@@ -385,17 +460,38 @@
if (junit4) {
// Let's use it!
+ Class[] formalParams;
+ Object[] actualParams;
+ if (useSingleMethodAdapter) {
+ formalParams = new Class[] {Class.class, String[].class};
+ actualParams = new Object[] {testClass, methods};
+ } else {
+ formalParams = new Class[] {Class.class};
+ actualParams = new Object[] {testClass};
+ }
suite =
(Test) junit4TestAdapterClass
- .getConstructor(new Class[] {Class.class}).
- newInstance(new Object[] {testClass});
+ .getConstructor(formalParams).
+ newInstance(actualParams);
} else {
// Use JUnit 3.
// try to extract a test suite automatically this
// will generate warnings if the class is no
// suitable Test
- suite = new TestSuite(testClass);
+ if (!testMethodsSpecified) {
+ suite = new TestSuite(testClass);
+ } else if (methods.length == 1) {
+ suite = TestSuite.createTest(testClass, methods[0]);
+ } else {
+ TestSuite testSuite = new TestSuite(testClass.getName());
+ for (int i = 0; i < methods.length; i++) {
+ testSuite.addTest(
+ TestSuite.createTest(testClass, methods[i]));
+ }
+ suite = testSuite;
+ }
+ }
}
}
@@ -670,11 +766,16 @@
* <tr><td>logtestlistenerevents</td><td>log TestListener events to
* System.out.</td><td>false</td></tr>
*
+ * <tr><td>methods</td><td>Comma-separated list of names of individual
+ * test methods to execute.
+ * </td><td>null</td></tr>
+ *
* </table>
* @param args the command line arguments.
* @throws IOException on error.
*/
public static void main(String[] args) throws IOException {
+ String[] methods = null;
boolean haltError = false;
boolean haltFail = false;
boolean stackfilter = true;
@@ -696,7 +797,15 @@
}
for (int i = 1; i < args.length; i++) {
- if (args[i].startsWith(Constants.HALT_ON_ERROR)) {
+ if (args[i].startsWith(Constants.METHOD_NAMES)) {
+ try {
+ String methodsList = args[i].substring(Constants.METHOD_NAMES.length());
+ methods = JUnitTest.parseTestMethodNamesList(methodsList);
+ } catch (IllegalArgumentException ex) {
+ System.err.println("Invalid specification of test method names: " + args[i]);
+ System.exit(ERRORS);
+ }
+ } else if (args[i].startsWith(Constants.HALT_ON_ERROR)) {
haltError = Project.toBoolean(args[i].substring(Constants.HALT_ON_ERROR.length()));
} else if (args[i].startsWith(Constants.HALT_ON_FAILURE)) {
haltFail = Project.toBoolean(args[i].substring(Constants.HALT_ON_FAILURE.length()));
@@ -744,18 +853,30 @@
java.io.BufferedReader reader =
new java.io.BufferedReader(new java.io.FileReader(args[0]));
String testCaseName;
+ String[] testMethodNames;
int code = 0;
boolean errorOccurred = false;
boolean failureOccurred = false;
String line = null;
while ((line = reader.readLine()) != null) {
StringTokenizer st = new StringTokenizer(line, ",");
- testCaseName = st.nextToken();
+ String testListSpec = st.nextToken();
+ int colonIndex = testListSpec.indexOf(':');
+ if (colonIndex == -1) {
+ testCaseName = testListSpec;
+ testMethodNames = null;
+ } else {
+ testCaseName = testListSpec.substring(0, colonIndex);
+ testMethodNames = JUnitTest.parseTestMethodNamesList(
+ testListSpec
+ .substring(colonIndex + 1)
+ .replace('+', ','));
+ }
JUnitTest t = new JUnitTest(testCaseName);
t.setTodir(new File(st.nextToken()));
t.setOutfile(st.nextToken());
t.setProperties(props);
- code = launch(t, haltError, stackfilter, haltFail,
+ code = launch(t, testMethodNames, haltError, stackfilter, haltFail,
showOut, outputToFormat,
logTestListenerEvents);
errorOccurred = (code == ERRORS);
@@ -783,7 +904,7 @@
JUnitTest t = new JUnitTest(args[0]);
t.setProperties(props);
returnCode = launch(
- t, haltError, stackfilter, haltFail,
+ t, methods, haltError, stackfilter, haltFail,
showOut, outputToFormat, logTestListenerEvents);
}
@@ -917,12 +1038,12 @@
/**
* @since Ant 1.6.2
*/
- private static int launch(JUnitTest t, boolean haltError,
+ private static int launch(JUnitTest t, String[] methods, boolean haltError,
boolean stackfilter, boolean haltFail,
boolean showOut, boolean outputToFormat,
boolean logTestListenerEvents) {
JUnitTestRunner runner =
- new JUnitTestRunner(t, haltError, stackfilter, haltFail, showOut,
+ new JUnitTestRunner(t, methods, haltError, stackfilter, haltFail, showOut,
logTestListenerEvents, null);
runner.forked = true;
runner.outputToFormatters = outputToFormat;
Added: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultParser.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultParser.java?rev=906782&view=auto
==============================================================================
--- ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultParser.java (added)
+++ ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultParser.java Fri Feb 5 02:51:40 2010
@@ -0,0 +1,265 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * Parser of XML-output generated by the JUnit XML formatter.
+ *
+ * @author Marian Petras
+ */
+final class XMLResultParser extends DefaultHandler {
+
+ /** */
+ private static final int STATE_OUT_OF_SCOPE = 1;
+ /** */
+ private static final int STATE_TESTSUITE = 2;
+ /** */
+ private static final int STATE_PROPERTIES = 3;
+ /** */
+ private static final int STATE_PROPERTY = 4;
+ /** */
+ private static final int STATE_TESTCASE = 8;
+ /** */
+ private static final int STATE_FAILURE = 12;
+ /** */
+ private static final int STATE_ERROR = 13;
+ /** */
+ private static final int STATE_OUTPUT_STD = 16;
+ /** */
+ private static final int STATE_OUTPUT_ERR = 17;
+
+ /** */
+ private int state = STATE_OUT_OF_SCOPE;
+ /** */
+ int unknownElemNestLevel = 0;
+
+ /** */
+ private final XMLReader xmlReader;
+ /** */
+ private String lastErrClassName = null;
+ /** */
+ private List lastErrMethodNames = null;
+ /** */
+ private String className;
+ /** */
+ private String methodName;
+
+ /** */
+ private List result = null;
+
+ /**
+ * Parses an XML file provided by a given reader.
+ * @param reader reader to read the XML file from
+ * @return list of Strings, each describing a single <code>JUnitTest</code>
+ * @exception java.io.IOException
+ * in case of troubles with reading the file
+ * @exception org.xml.sax.SAXException
+ * if initialization of the parser failed
+ */
+ static List parseResultsFile(Reader reader) throws IOException, SAXException {
+ XMLResultParser parser = new XMLResultParser();
+ parser.xmlReader.parse(new InputSource(reader));
+ return (parser.result != null) ? parser.result
+ : Collections.EMPTY_LIST;
+ }
+
+ /** Creates a new instance of XMLResultParser */
+ private XMLResultParser() throws SAXException {
+ xmlReader = XMLReaderFactory.createXMLReader();
+ xmlReader.setContentHandler(this);
+ }
+
+ /**
+ */
+ public void startElement(String uri,
+ String localName,
+ String qName,
+ Attributes attrs) throws SAXException {
+ switch (state) {
+ case STATE_PROPERTIES:
+ if (qName.equals("property")) {
+ state = STATE_PROPERTY;
+ } else {
+ startUnknownElem();
+ }
+ break;
+ case STATE_TESTSUITE:
+ if (qName.equals("testcase")) {
+ className = attrs.getValue("classname");
+ methodName = attrs.getValue("name");
+ state = STATE_TESTCASE;
+ } else if (qName.equals("system-out")) {
+ state = STATE_OUTPUT_STD;
+ } else if (qName.equals("system-err")) {
+ state = STATE_OUTPUT_ERR;
+ } else if (qName.equals("properties")) {
+ state = STATE_PROPERTIES;
+ } else {
+ startUnknownElem();
+ }
+ break;
+ case STATE_TESTCASE:
+ if (qName.equals("failure")) {
+ state = STATE_FAILURE;
+ } else if (qName.equals("error")) {
+ state = STATE_ERROR;
+ } else {
+ startUnknownElem();
+ }
+ if (state >= 0) { //i.e. the element is "failure" or "error"
+ if ((className != null) && (methodName != null)) {
+ if (className.equals(lastErrClassName)) {
+ lastErrMethodNames.add(methodName);
+ } else {
+ maybeSaveLastErrJUnitTest();
+ }
+
+ lastErrClassName = className;
+ if (lastErrMethodNames == null) {
+ lastErrMethodNames = new ArrayList(5);
+ }
+ lastErrMethodNames.add(methodName);
+ }
+ }
+ break;
+ case STATE_OUT_OF_SCOPE:
+ if (qName.equals("testsuite")) {
+ state = STATE_TESTSUITE;
+ } else {
+ startUnknownElem();
+ }
+ break;
+ case STATE_PROPERTY:
+ case STATE_FAILURE:
+ case STATE_ERROR:
+ case STATE_OUTPUT_STD:
+ case STATE_OUTPUT_ERR:
+ startUnknownElem();
+ break;
+ default:
+ unknownElemNestLevel++;
+ break;
+ }
+ }
+
+ /**
+ */
+ public void endElement(String uri,
+ String localName,
+ String qName) throws SAXException {
+ switch (state) {
+ case STATE_PROPERTIES:
+ state = STATE_TESTSUITE;
+ break;
+ case STATE_TESTSUITE:
+ maybeSaveLastErrJUnitTest();
+ state = STATE_OUT_OF_SCOPE;
+ break;
+ case STATE_TESTCASE:
+ state = STATE_TESTSUITE;
+ break;
+ case STATE_OUT_OF_SCOPE:
+ break;
+ case STATE_PROPERTY:
+ state = STATE_PROPERTIES;
+ break;
+ case STATE_FAILURE:
+ case STATE_ERROR:
+ state = STATE_TESTCASE;
+ break;
+ case STATE_OUTPUT_STD:
+ case STATE_OUTPUT_ERR:
+ state = STATE_TESTSUITE;
+ break;
+ default:
+ if (--unknownElemNestLevel == 0) {
+ state = -state;
+ }
+ break;
+ }
+ }
+
+ /**
+ */
+ private void startUnknownElem() {
+ state = -state;
+ unknownElemNestLevel++;
+ }
+
+ /**
+ */
+ private void maybeSaveLastErrJUnitTest() {
+ if (lastErrClassName == null) {
+ return;
+ }
+
+ StringBuffer buf = new StringBuffer(20);
+ buf.append(lastErrClassName).append(':');
+ buf.append(lastErrMethodNames.get(0));
+ int methodsCount = lastErrMethodNames.size();
+ if (methodsCount > 1) {
+ for (int i = 1; i < methodsCount; i++) {
+ buf.append(',').append(lastErrMethodNames.get(i));
+ }
+ }
+ if (result == null) {
+ result = new ArrayList(10);
+ }
+ result.add(buf.toString());
+
+ lastErrClassName = null;
+ lastErrMethodNames.clear();
+ }
+
+}
Propchange: ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/BatchTestTest.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/BatchTestTest.java?rev=906782&view=auto
==============================================================================
--- ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/BatchTestTest.java (added)
+++ ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/BatchTestTest.java Fri Feb 5 02:51:40 2010
@@ -0,0 +1,129 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.ComparisonFailure;
+import junit.framework.TestCase;
+
+/**
+ *
+ * @author Marian Petras
+ */
+public class BatchTestTest extends TestCase {
+
+ public BatchTestTest(String testName) {
+ super(testName);
+ }
+
+
+ public void testParseTestMethodNamesList() {
+ try {
+ JUnitTest.parseTestMethodNamesList(null);
+ fail("IllegalArgumentException expected when the param is <null>");
+ } catch (IllegalArgumentException ex) {
+ //this is an expected exception
+ }
+
+ assertEquals(new String[0], JUnitTest.parseTestMethodNamesList(""));
+ assertEquals(new String[0], JUnitTest.parseTestMethodNamesList(" "));
+ assertEquals(new String[0], JUnitTest.parseTestMethodNamesList(" "));
+
+ checkParseCausesIAE(",");
+ checkParseCausesIAE(" ,");
+ checkParseCausesIAE(", ");
+ checkParseCausesIAE(" , ");
+ checkParseCausesIAE(",a");
+ checkParseCausesIAE(" ,a");
+ checkParseCausesIAE(" ,a");
+ checkParseCausesIAE(" , a");
+ checkParseCausesIAE(" ,a ");
+ checkParseCausesIAE(" ,a ,");
+ checkParseCausesIAE("ab,,cd");
+ checkParseCausesIAE("ab, ,cd");
+ checkParseCausesIAE("ab, ,cd");
+ checkParseCausesIAE("ab, ,cd,");
+ checkParseCausesIAE(",ab, ,cd,");
+
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc"));
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc "));
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList(" abc"));
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList(" abc "));
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc "));
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc,"));
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc, "));
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc ,"));
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc , "));
+ assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList(" abc ,"));
+
+ /* legal Java identifiers: */
+ assertEquals(new String[] {"a"}, JUnitTest.parseTestMethodNamesList("a"));
+ assertEquals(new String[] {"a1"}, JUnitTest.parseTestMethodNamesList("a1"));
+ assertEquals(new String[] {"a$"}, JUnitTest.parseTestMethodNamesList("a$"));
+ assertEquals(new String[] {"a$1"}, JUnitTest.parseTestMethodNamesList("a$1"));
+ assertEquals(new String[] {"_bc"}, JUnitTest.parseTestMethodNamesList("_bc"));
+ assertEquals(new String[] {"___"}, JUnitTest.parseTestMethodNamesList("___"));
+
+ /* illegal Java identifiers: */
+ checkParseCausesIAE("1");
+ checkParseCausesIAE("1a");
+ checkParseCausesIAE("1ab");
+ checkParseCausesIAE("1abc");
+ checkParseCausesIAE("1abc d");
+ checkParseCausesIAE("1abc de");
+ checkParseCausesIAE("1abc def");
+ checkParseCausesIAE("1abc def,");
+ checkParseCausesIAE(",1abc def");
+
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc,def"));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc,def,"));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc,def "));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc, def"));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc, def "));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc ,def"));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc ,def "));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc , def"));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc , def "));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc,def"));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc,def "));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc, def"));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc, def "));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc ,def"));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc ,def "));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc , def"));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc , def "));
+ assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc , def ,"));
+ }
+
+ private static void checkParseCausesIAE(String param) {
+ try {
+ JUnitTest.parseTestMethodNamesList(param);
+ fail("IllegalArgumentException expected when the param is \"" + param + '"');
+ } catch (IllegalArgumentException ex) {
+ //this is an expected exception
+ }
+ }
+
+ private static void assertEquals(String[] expected, String[] actual) {
+ assertEquals(null, expected, actual);
+ }
+
+ private static void assertEquals(String message,
+ String[] expected,
+ String[] actual) {
+ if ((expected == null) && (actual == null)) {
+ return;
+ }
+ if (expected.length != actual.length) {
+ throw new ComparisonFailure(message,
+ expected.toString(),
+ actual.toString());
+ }
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], actual[i]);
+ }
+ }
+
+}
Propchange: ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/BatchTestTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java
URL: http://svn.apache.org/viewvc/ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java?rev=906782&r1=906781&r2=906782&view=diff
==============================================================================
--- ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java (original)
+++ ant/core/branches/run-single-test-method/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java Fri Feb 5 02:51:40 2010
@@ -33,6 +33,21 @@
super(name);
}
+ // check that a valid method name generates no errors
+ public void testValidMethod(){
+ TestRunner runner = createRunnerForTestMethod(ValidMethodTestCase.class,"testA");
+ runner.run();
+ assertEquals(runner.getFormatter().getError(), JUnitTestRunner.SUCCESS, runner.getRetCode());
+ }
+
+ // check that having an invalid method name generates an error
+ public void testInvalidMethod(){
+ TestRunner runner = createRunnerForTestMethod(InvalidMethodTestCase.class,"testInvalid");
+ runner.run();
+ String error = runner.getFormatter().getError();
+ assertEquals(error, JUnitTestRunner.ERRORS, runner.getRetCode());
+ }
+
// check that having no suite generates no errors
public void testNoSuite(){
TestRunner runner = createRunner(NoSuiteTestCase.class);
@@ -87,14 +102,22 @@
}
protected TestRunner createRunner(Class clazz){
- return new TestRunner(new JUnitTest(clazz.getName()), true, true, true);
+ return new TestRunner(new JUnitTest(clazz.getName()), null,
+ true, true, true);
}
+ protected TestRunner createRunnerForTestMethod(Class clazz, String method){
+ return new TestRunner(new JUnitTest(clazz.getName()), new String[] {method},
+ true, true, true);
+ }
+
// the test runner that wrap the dummy formatter that interests us
private final static class TestRunner extends JUnitTestRunner {
private ResultFormatter formatter = new ResultFormatter();
- TestRunner(JUnitTest test, boolean haltonerror, boolean filtertrace, boolean haltonfailure){
- super(test, haltonerror, filtertrace, haltonfailure, TestRunner.class.getClassLoader());
+ TestRunner(JUnitTest test, String[] methods, boolean haltonerror,
+ boolean filtertrace, boolean haltonfailure){
+ super(test, methods, haltonerror, filtertrace, haltonfailure,
+ false, false, TestRunner.class.getClassLoader());
// use the classloader that loaded this class otherwise
// it will not be able to run inner classes if this test
// is ran in non-forked mode.
@@ -133,6 +156,24 @@
public static class NoTestCase {
}
+ public static class InvalidMethodTestCase extends TestCase {
+ public InvalidMethodTestCase(String name){ super(name); }
+ public void testA(){
+ throw new NullPointerException("thrown on purpose");
+ }
+ }
+
+ public static class ValidMethodTestCase extends TestCase {
+ public ValidMethodTestCase(String name){ super(name); }
+ public void testA(){
+ // expected to be executed
+ }
+ public void testB(){
+ // should not be executed
+ throw new NullPointerException("thrown on purpose");
+ }
+ }
+
public static class InvalidTestCase extends TestCase {
public InvalidTestCase(String name){
super(name);
Re: svn commit: r906782 - in /ant/core/branches/run-single-test-method:
docs/manual/OptionalTasks/ lib/optional/ src/main/org/apache/tools/ant/taskdefs/optional/junit/
src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/
Posted by Jesse Glick <je...@sun.com>.
Stefan Bodewig wrote:
>>> <td valign="top">rerunfailed</td>
>
> This part has been covered - in a totally different way - by the failure
> recorder in 1.8.0.
I'll check if this is is actually needed by anything; may be possible to delete.
> You better get that re-licensed or we won't be able to use it.
Probably an oversight.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org
Re: svn commit: r906782 - in /ant/core/branches/run-single-test-method: docs/manual/OptionalTasks/ lib/optional/ src/main/org/apache/tools/ant/taskdefs/optional/junit/ src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/
Posted by Stefan Bodewig <bo...@apache.org>.
On 2010-02-05, <jg...@apache.org> wrote:
> Attempting to forward-port patch made against 1.7.1.
>> <td valign="top">rerunfailed</td>
>> <td valign="top">Run only those test methods that failed during the previous
>> execution. <em>Since Ant 1.7.1</em>
>> <p>Results of the previous execution are taken from XML report files
>> generated by the XML <a href="#formatter">formatter</a>.<br />
>> The report files are searched for in the target directory for reports,
>> i.e. in the directory specified by the <code>todir</code> attribute.</p>
>> </td>
>> <td align="center" valign="top">No; default is <code>off</code>.</td>
>> </tr>
>> <tr>
This part has been covered - in a totally different way - by the failure
recorder in 1.8.0. I'm not convinced of either approach 8-)
>>>> ant/core/branches/run-single-test-method/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java Fri Feb 5 02:51:40 2010
> @@ -0,0 +1,250 @@
>> /*
>> * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
>> *
>> * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
>> *
>> * The contents of this file are subject to the terms of either the GNU
>> * General Public License Version 2 only ("GPL") or the Common
>> * Development and Distribution License("CDDL") (collectively, the
>> * "License"). You may not use this file except in compliance with the
>> * License.
You better get that re-licensed or we won't be able to use it.
Stefan
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org