git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@953761 13f79535-47bb-0310-9956-ffa450edef68master
@@ -61,6 +61,9 @@ Other changes: | |||||
overwrite attribute that is consistent with <copy>'s attribute | overwrite attribute that is consistent with <copy>'s attribute | ||||
names. | names. | ||||
* You can now specify a list of methods to run in a JUnit test case. | |||||
Bugzilla Report 34748. | |||||
Changes from Ant 1.8.0 TO Ant 1.8.1 | Changes from Ant 1.8.0 TO Ant 1.8.1 | ||||
=================================== | =================================== | ||||
@@ -350,7 +350,7 @@ | |||||
classname="org.apache.xalan.trace.TraceListenerEx3" | classname="org.apache.xalan.trace.TraceListenerEx3" | ||||
classpathref="classpath" ignoresystemclasses="true"/> | classpathref="classpath" ignoresystemclasses="true"/> | ||||
<available property="junit.present" | <available property="junit.present" | ||||
classname="junit.framework.TestCase" | |||||
classname="org.junit.Test" | |||||
classpathref="classpath" ignoresystemclasses="true"/> | classpathref="classpath" ignoresystemclasses="true"/> | ||||
<available property="antunit.present" | <available property="antunit.present" | ||||
classname="org.apache.ant.antunit.AntUnit" | classname="org.apache.ant.antunit.AntUnit" | ||||
@@ -430,6 +430,26 @@ the name of the resulting class (without suffix). It defaults to <i>java-tmp-dir | |||||
<td valign="top">Name of the test class.</td> | <td valign="top">Name of the test class.</td> | ||||
<td align="center">Yes</td> | <td align="center">Yes</td> | ||||
</tr> | </tr> | ||||
<tr> | |||||
<td valign="top">methods</td> | |||||
<td valign="top">Comma-separated list of names of test case methods to execute. | |||||
<em>Since 1.8.2</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> | <tr> | ||||
<td valign="top">fork</td> | <td valign="top">fork</td> | ||||
<td valign="top">Run the tests in a separate VM. | <td valign="top">Run the tests in a separate VM. | ||||
@@ -45,7 +45,7 @@ jasper-compiler.version=4.1.36 | |||||
jasper-runtime.version=${jasper-compiler.version} | jasper-runtime.version=${jasper-compiler.version} | ||||
jdepend.version=2.9.1 | jdepend.version=2.9.1 | ||||
jruby.version=0.9.8 | jruby.version=0.9.8 | ||||
junit.version=3.8.2 | |||||
junit.version=4.8.1 | |||||
jsch.version=0.1.42 | jsch.version=0.1.42 | ||||
jython.version=2.1 | jython.version=2.1 | ||||
#log4j 1.2.15 requires JMS and a few other Sun jars that are not in the m2 repo | #log4j 1.2.15 requires JMS and a few other Sun jars that are not in the m2 repo | ||||
@@ -1,3 +1,3 @@ | |||||
The file junit-3.8.2.jar is version 3.8.2 of JUnit, see the file LICENSE.junit.html | |||||
The file junit-4.8.1.jar is version 4.8.1 of JUnit, see the file LICENSE.junit.html | |||||
for the terms of distribution. For more information about JUnit or | for the terms of distribution. For more information about JUnit or | ||||
the latest release, see <http://www.junit.org/>. | the latest release, see <http://www.junit.org/>. |
@@ -23,6 +23,7 @@ package org.apache.tools.ant.taskdefs.optional.junit; | |||||
*/ | */ | ||||
public class Constants { | public class Constants { | ||||
static final String METHOD_NAMES = "methods="; | |||||
static final String HALT_ON_ERROR = "haltOnError="; | static final String HALT_ON_ERROR = "haltOnError="; | ||||
static final String HALT_ON_FAILURE = "haltOnFailure="; | static final String HALT_ON_FAILURE = "haltOnFailure="; | ||||
static final String FILTERTRACE = "filtertrace="; | static final String FILTERTRACE = "filtertrace="; | ||||
@@ -0,0 +1,227 @@ | |||||
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You 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.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; | |||||
} | |||||
} | |||||
} |
@@ -728,6 +728,7 @@ public class JUnitTask extends Task { | |||||
new SplitClassLoader(myLoader, path, getProject(), | new SplitClassLoader(myLoader, path, getProject(), | ||||
new String[] { | new String[] { | ||||
"BriefJUnitResultFormatter", | "BriefJUnitResultFormatter", | ||||
"JUnit4TestMethodAdapter", | |||||
"JUnitResultFormatter", | "JUnitResultFormatter", | ||||
"JUnitTaskMirrorImpl", | "JUnitTaskMirrorImpl", | ||||
"JUnitTestRunner", | "JUnitTestRunner", | ||||
@@ -751,6 +752,8 @@ public class JUnitTask extends Task { | |||||
* @since Ant 1.2 | * @since Ant 1.2 | ||||
*/ | */ | ||||
public void execute() throws BuildException { | public void execute() throws BuildException { | ||||
checkMethodLists(); | |||||
setupJUnitDelegate(); | setupJUnitDelegate(); | ||||
List testLists = new ArrayList(); | List testLists = new ArrayList(); | ||||
@@ -851,6 +854,9 @@ public class JUnitTask extends Task { | |||||
while (iter.hasNext()) { | while (iter.hasNext()) { | ||||
test = (JUnitTest) iter.next(); | test = (JUnitTest) iter.next(); | ||||
printDual(writer, logWriter, test.getName()); | printDual(writer, logWriter, test.getName()); | ||||
if (test.getMethods() != null) { | |||||
printDual(writer, logWriter, ":" + test.getMethodsString().replace(',', '+')); | |||||
} | |||||
if (test.getTodir() == null) { | if (test.getTodir() == null) { | ||||
printDual(writer, logWriter, | printDual(writer, logWriter, | ||||
"," + getProject().resolveFile(".")); | "," + getProject().resolveFile(".")); | ||||
@@ -922,6 +928,9 @@ public class JUnitTask extends Task { | |||||
cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner"); | cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner"); | ||||
if (casesFile == null) { | if (casesFile == null) { | ||||
cmd.createArgument().setValue(test.getName()); | cmd.createArgument().setValue(test.getName()); | ||||
if (test.getMethods() != null) { | |||||
cmd.createArgument().setValue(Constants.METHOD_NAMES + test.getMethodsString()); | |||||
} | |||||
} else { | } else { | ||||
log("Running multiple tests in the same VM", Project.MSG_VERBOSE); | log("Running multiple tests in the same VM", Project.MSG_VERBOSE); | ||||
cmd.createArgument().setValue(Constants.TESTSFILE + casesFile); | cmd.createArgument().setValue(Constants.TESTSFILE + casesFile); | ||||
@@ -1322,7 +1331,7 @@ public class JUnitTask extends Task { | |||||
if (classLoader != null) { | if (classLoader != null) { | ||||
classLoader.setThreadContextLoader(); | classLoader.setThreadContextLoader(); | ||||
} | } | ||||
runner = delegate.newJUnitTestRunner(test, test.getHaltonerror(), | |||||
runner = delegate.newJUnitTestRunner(test, test.getMethods(), test.getHaltonerror(), | |||||
test.getFiltertrace(), | test.getFiltertrace(), | ||||
test.getHaltonfailure(), false, | test.getHaltonfailure(), false, | ||||
true, classLoader); | true, classLoader); | ||||
@@ -1407,6 +1416,29 @@ public class JUnitTask extends Task { | |||||
return Enumerations.fromCompound(enums); | return Enumerations.fromCompound(enums); | ||||
} | } | ||||
/** | |||||
* 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 1.8.2 | |||||
*/ | |||||
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 an enumeration listing each test, then each batchtest | ||||
* @return enumeration | * @return enumeration | ||||
@@ -55,6 +55,7 @@ public interface JUnitTaskMirror { | |||||
/** | /** | ||||
* Create a new test runner for a test. | * Create a new test runner for a test. | ||||
* @param test the test to run. | * @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 haltOnError if true halt the tests if an error occurs. | ||||
* @param filterTrace if true filter the stack traces. | * @param filterTrace if true filter the stack traces. | ||||
* @param haltOnFailure if true halt the test if a failure occurs. | * @param haltOnFailure if true halt the test if a failure occurs. | ||||
@@ -63,7 +64,7 @@ public interface JUnitTaskMirror { | |||||
* @param classLoader the classloader to use to create the runner. | * @param classLoader the classloader to use to create the runner. | ||||
* @return the test 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 filterTrace, boolean haltOnFailure, boolean showOutput, | ||||
boolean logTestListenerEvents, AntClassLoader classLoader); | boolean logTestListenerEvents, AntClassLoader classLoader); | ||||
@@ -60,9 +60,10 @@ public final class JUnitTaskMirrorImpl implements JUnitTaskMirror { | |||||
/** {@inheritDoc}. */ | /** {@inheritDoc}. */ | ||||
public JUnitTaskMirror.JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, | public JUnitTaskMirror.JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, | ||||
String[] methods, | |||||
boolean haltOnError, boolean filterTrace, boolean haltOnFailure, | boolean haltOnError, boolean filterTrace, boolean haltOnFailure, | ||||
boolean showOutput, boolean logTestListenerEvents, AntClassLoader classLoader) { | boolean showOutput, boolean logTestListenerEvents, AntClassLoader classLoader) { | ||||
return new JUnitTestRunner(test, haltOnError, filterTrace, haltOnFailure, | |||||
return new JUnitTestRunner(test, methods, haltOnError, filterTrace, haltOnFailure, | |||||
showOutput, logTestListenerEvents, classLoader); | showOutput, logTestListenerEvents, classLoader); | ||||
} | } | ||||
@@ -22,6 +22,7 @@ import java.util.Enumeration; | |||||
import java.util.Hashtable; | import java.util.Hashtable; | ||||
import java.util.Properties; | import java.util.Properties; | ||||
import java.util.Vector; | import java.util.Vector; | ||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.PropertyHelper; | import org.apache.tools.ant.PropertyHelper; | ||||
@@ -41,6 +42,19 @@ public class JUnitTest extends BaseTest implements Cloneable { | |||||
/** the name of the test case */ | /** the name of the test case */ | ||||
private String name = null; | 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 */ | /** the name of the result file */ | ||||
private String outfile = null; | private String outfile = null; | ||||
@@ -73,11 +87,53 @@ public class JUnitTest extends BaseTest implements Cloneable { | |||||
* @param filtertrace if true filter stack traces. | * @param filtertrace if true filter stack traces. | ||||
*/ | */ | ||||
public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure, | 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 1.8.2 | |||||
*/ | |||||
public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure, | |||||
boolean filtertrace, String[] methods) { | |||||
this.name = name; | this.name = name; | ||||
this.haltOnError = haltOnError; | this.haltOnError = haltOnError; | ||||
this.haltOnFail = haltOnFailure; | this.haltOnFail = haltOnFailure; | ||||
this.filtertrace = filtertrace; | 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 1.8.2 | |||||
*/ | |||||
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 1.8.2 | |||||
*/ | |||||
void setMethods(String[] value) { | |||||
methods = value; | |||||
methodsSpecified = (value != null); | |||||
methodsList = null; | |||||
} | } | ||||
/** | /** | ||||
@@ -96,6 +152,189 @@ public class JUnitTest extends BaseTest implements Cloneable { | |||||
outfile = value; | outfile = value; | ||||
} | } | ||||
/** | |||||
* 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 1.8.2 | |||||
*/ | |||||
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 1.8.2 | |||||
*/ | |||||
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 1.8.2 | |||||
*/ | |||||
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 1.8.2 | |||||
*/ | |||||
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 1.8.2 | |||||
*/ | |||||
public 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. | * Get the name of the test class. | ||||
* @return the name of the test. | * @return the name of the test. | ||||
@@ -163,6 +163,9 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
*/ | */ | ||||
private static String crashFile = null; | 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 | * Constructor for fork=true or when the user hasn't specified a | ||||
* classpath. | * classpath. | ||||
@@ -205,7 +208,26 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
public JUnitTestRunner(JUnitTest test, boolean haltOnError, | public JUnitTestRunner(JUnitTest test, boolean haltOnError, | ||||
boolean filtertrace, boolean haltOnFailure, | boolean filtertrace, boolean haltOnFailure, | ||||
boolean showOutput, boolean logTestListenerEvents) { | 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 1.8.2 | |||||
*/ | |||||
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); | logTestListenerEvents, null); | ||||
} | } | ||||
@@ -254,12 +276,26 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
boolean filtertrace, boolean haltOnFailure, | boolean filtertrace, boolean haltOnFailure, | ||||
boolean showOutput, boolean logTestListenerEvents, | boolean showOutput, boolean logTestListenerEvents, | ||||
ClassLoader loader) { | ClassLoader loader) { | ||||
this(test, null, haltOnError, filtertrace, haltOnFailure, showOutput, | |||||
logTestListenerEvents, loader); | |||||
} | |||||
/** | |||||
* Constructor to use when the user has specified a classpath. | |||||
* @since 1.8.2 | |||||
*/ | |||||
public JUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError, | |||||
boolean filtertrace, boolean haltOnFailure, | |||||
boolean showOutput, boolean logTestListenerEvents, | |||||
ClassLoader loader) { | |||||
JUnitTestRunner.filtertrace = filtertrace; | JUnitTestRunner.filtertrace = filtertrace; | ||||
this.junitTest = test; | this.junitTest = test; | ||||
this.haltOnError = haltOnError; | this.haltOnError = haltOnError; | ||||
this.haltOnFailure = haltOnFailure; | this.haltOnFailure = haltOnFailure; | ||||
this.showOutput = showOutput; | this.showOutput = showOutput; | ||||
this.logTestListenerEvents = logTestListenerEvents; | this.logTestListenerEvents = logTestListenerEvents; | ||||
this.methods = methods; | |||||
this.loader = loader; | this.loader = loader; | ||||
} | } | ||||
@@ -340,9 +376,12 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
loader); | loader); | ||||
} | } | ||||
final boolean testMethodsSpecified = (methods != null); | |||||
// check for a static suite method first, even when using | // check for a static suite method first, even when using | ||||
// JUnit 4 | // JUnit 4 | ||||
Method suiteMethod = null; | Method suiteMethod = null; | ||||
if (!testMethodsSpecified) { | |||||
try { | try { | ||||
// check if there is a suite method | // check if there is a suite method | ||||
suiteMethod = testClass.getMethod("suite", new Class[0]); | suiteMethod = testClass.getMethod("suite", new Class[0]); | ||||
@@ -350,6 +389,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
// no appropriate suite method found. We don't report any | // no appropriate suite method found. We don't report any | ||||
// error here since it might be perfectly normal. | // error here since it might be perfectly normal. | ||||
} | } | ||||
} | |||||
if (suiteMethod != null) { | if (suiteMethod != null) { | ||||
// if there is a suite method available, then try | // if there is a suite method available, then try | ||||
@@ -359,7 +399,23 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
} else { | } else { | ||||
Class junit4TestAdapterClass = null; | 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 | // Check for JDK 5 first. Will *not* help on JDK 1.4 | ||||
// if only junit-4.0.jar in CP because in that case | // if only junit-4.0.jar in CP because in that case | ||||
// linkage of whole task will already have failed! But | // linkage of whole task will already have failed! But | ||||
@@ -373,29 +429,69 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
if (loader == null) { | if (loader == null) { | ||||
junit4TestAdapterClass = | junit4TestAdapterClass = | ||||
Class.forName(JUNIT_4_TEST_ADAPTER); | 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 { | } else { | ||||
junit4TestAdapterClass = | junit4TestAdapterClass = | ||||
Class.forName(JUNIT_4_TEST_ADAPTER, | Class.forName(JUNIT_4_TEST_ADAPTER, | ||||
true, loader); | true, loader); | ||||
if (testMethodsSpecified) { | |||||
junit4TestAdapterClass = | |||||
Class.forName( | |||||
"org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter", | |||||
true, loader); | |||||
useSingleMethodAdapter = true; | |||||
} | |||||
} | } | ||||
} catch (ClassNotFoundException e) { | } catch (ClassNotFoundException e) { | ||||
// OK, fall back to JUnit 3. | // OK, fall back to JUnit 3. | ||||
} | } | ||||
} | |||||
junit4 = junit4TestAdapterClass != null; | junit4 = junit4TestAdapterClass != null; | ||||
if (junit4) { | if (junit4) { | ||||
// Let's use it! | // 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 = | suite = | ||||
(Test) junit4TestAdapterClass | (Test) junit4TestAdapterClass | ||||
.getConstructor(new Class[] {Class.class}). | |||||
newInstance(new Object[] {testClass}); | |||||
.getConstructor(formalParams). | |||||
newInstance(actualParams); | |||||
} else { | } else { | ||||
// Use JUnit 3. | // Use JUnit 3. | ||||
// try to extract a test suite automatically this | // try to extract a test suite automatically this | ||||
// will generate warnings if the class is no | // will generate warnings if the class is no | ||||
// suitable Test | // 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 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
* <tr><td>logtestlistenerevents</td><td>log TestListener events to | * <tr><td>logtestlistenerevents</td><td>log TestListener events to | ||||
* System.out.</td><td>false</td></tr> | * 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> | * </table> | ||||
* @param args the command line arguments. | * @param args the command line arguments. | ||||
* @throws IOException on error. | * @throws IOException on error. | ||||
*/ | */ | ||||
public static void main(String[] args) throws IOException { | public static void main(String[] args) throws IOException { | ||||
String[] methods = null; | |||||
boolean haltError = false; | boolean haltError = false; | ||||
boolean haltFail = false; | boolean haltFail = false; | ||||
boolean stackfilter = true; | boolean stackfilter = true; | ||||
@@ -696,7 +797,15 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
} | } | ||||
for (int i = 1; i < args.length; i++) { | 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())); | haltError = Project.toBoolean(args[i].substring(Constants.HALT_ON_ERROR.length())); | ||||
} else if (args[i].startsWith(Constants.HALT_ON_FAILURE)) { | } else if (args[i].startsWith(Constants.HALT_ON_FAILURE)) { | ||||
haltFail = Project.toBoolean(args[i].substring(Constants.HALT_ON_FAILURE.length())); | haltFail = Project.toBoolean(args[i].substring(Constants.HALT_ON_FAILURE.length())); | ||||
@@ -744,18 +853,30 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
java.io.BufferedReader reader = | java.io.BufferedReader reader = | ||||
new java.io.BufferedReader(new java.io.FileReader(args[0])); | new java.io.BufferedReader(new java.io.FileReader(args[0])); | ||||
String testCaseName; | String testCaseName; | ||||
String[] testMethodNames; | |||||
int code = 0; | int code = 0; | ||||
boolean errorOccurred = false; | boolean errorOccurred = false; | ||||
boolean failureOccurred = false; | boolean failureOccurred = false; | ||||
String line = null; | String line = null; | ||||
while ((line = reader.readLine()) != null) { | while ((line = reader.readLine()) != null) { | ||||
StringTokenizer st = new StringTokenizer(line, ","); | 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); | JUnitTest t = new JUnitTest(testCaseName); | ||||
t.setTodir(new File(st.nextToken())); | t.setTodir(new File(st.nextToken())); | ||||
t.setOutfile(st.nextToken()); | t.setOutfile(st.nextToken()); | ||||
t.setProperties(props); | t.setProperties(props); | ||||
code = launch(t, haltError, stackfilter, haltFail, | |||||
code = launch(t, testMethodNames, haltError, stackfilter, haltFail, | |||||
showOut, outputToFormat, | showOut, outputToFormat, | ||||
logTestListenerEvents); | logTestListenerEvents); | ||||
errorOccurred = (code == ERRORS); | errorOccurred = (code == ERRORS); | ||||
@@ -783,7 +904,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
JUnitTest t = new JUnitTest(args[0]); | JUnitTest t = new JUnitTest(args[0]); | ||||
t.setProperties(props); | t.setProperties(props); | ||||
returnCode = launch( | returnCode = launch( | ||||
t, haltError, stackfilter, haltFail, | |||||
t, methods, haltError, stackfilter, haltFail, | |||||
showOut, outputToFormat, logTestListenerEvents); | showOut, outputToFormat, logTestListenerEvents); | ||||
} | } | ||||
@@ -917,12 +1038,12 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
/** | /** | ||||
* @since Ant 1.6.2 | * @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 stackfilter, boolean haltFail, | ||||
boolean showOut, boolean outputToFormat, | boolean showOut, boolean outputToFormat, | ||||
boolean logTestListenerEvents) { | boolean logTestListenerEvents) { | ||||
JUnitTestRunner runner = | JUnitTestRunner runner = | ||||
new JUnitTestRunner(t, haltError, stackfilter, haltFail, showOut, | |||||
new JUnitTestRunner(t, methods, haltError, stackfilter, haltFail, showOut, | |||||
logTestListenerEvents, null); | logTestListenerEvents, null); | ||||
runner.forked = true; | runner.forked = true; | ||||
runner.outputToFormatters = outputToFormat; | runner.outputToFormatters = outputToFormat; | ||||
@@ -0,0 +1,142 @@ | |||||
/* | |||||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||||
* contributor license agreements. See the NOTICE file distributed with | |||||
* this work for additional information regarding copyright ownership. | |||||
* The ASF licenses this file to You 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 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]); | |||||
} | |||||
} | |||||
} |
@@ -33,6 +33,22 @@ public class JUnitTestRunnerTest extends TestCase { | |||||
super(name); | 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(); | |||||
// might be FAILURES or ERRORS depending on JUnit version? | |||||
assertTrue(error, runner.getRetCode() != JUnitTestRunner.SUCCESS); | |||||
} | |||||
// check that having no suite generates no errors | // check that having no suite generates no errors | ||||
public void testNoSuite(){ | public void testNoSuite(){ | ||||
TestRunner runner = createRunner(NoSuiteTestCase.class); | TestRunner runner = createRunner(NoSuiteTestCase.class); | ||||
@@ -87,14 +103,22 @@ public class JUnitTestRunnerTest extends TestCase { | |||||
} | } | ||||
protected TestRunner createRunner(Class clazz){ | 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 | // the test runner that wrap the dummy formatter that interests us | ||||
private final static class TestRunner extends JUnitTestRunner { | private final static class TestRunner extends JUnitTestRunner { | ||||
private ResultFormatter formatter = new ResultFormatter(); | 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 | // use the classloader that loaded this class otherwise | ||||
// it will not be able to run inner classes if this test | // it will not be able to run inner classes if this test | ||||
// is ran in non-forked mode. | // is ran in non-forked mode. | ||||
@@ -133,6 +157,24 @@ public class JUnitTestRunnerTest extends TestCase { | |||||
public static class NoTestCase { | 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 static class InvalidTestCase extends TestCase { | ||||
public InvalidTestCase(String name){ | public InvalidTestCase(String name){ | ||||
super(name); | super(name); | ||||