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