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 | |||
| 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 | |||
| =================================== | |||
| @@ -350,7 +350,7 @@ | |||
| classname="org.apache.xalan.trace.TraceListenerEx3" | |||
| classpathref="classpath" ignoresystemclasses="true"/> | |||
| <available property="junit.present" | |||
| classname="junit.framework.TestCase" | |||
| classname="org.junit.Test" | |||
| classpathref="classpath" ignoresystemclasses="true"/> | |||
| <available property="antunit.present" | |||
| 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 align="center">Yes</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">methods</td> | |||
| <td valign="top">Comma-separated list of names of test case methods to execute. | |||
| <em>Since 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> | |||
| <td valign="top">fork</td> | |||
| <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} | |||
| jdepend.version=2.9.1 | |||
| jruby.version=0.9.8 | |||
| junit.version=3.8.2 | |||
| junit.version=4.8.1 | |||
| jsch.version=0.1.42 | |||
| jython.version=2.1 | |||
| #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 | |||
| the latest release, see <http://www.junit.org/>. | |||
| @@ -23,6 +23,7 @@ package org.apache.tools.ant.taskdefs.optional.junit; | |||
| */ | |||
| public class Constants { | |||
| static final String METHOD_NAMES = "methods="; | |||
| static final String HALT_ON_ERROR = "haltOnError="; | |||
| static final String HALT_ON_FAILURE = "haltOnFailure="; | |||
| static final String FILTERTRACE = "filtertrace="; | |||
| @@ -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 String[] { | |||
| "BriefJUnitResultFormatter", | |||
| "JUnit4TestMethodAdapter", | |||
| "JUnitResultFormatter", | |||
| "JUnitTaskMirrorImpl", | |||
| "JUnitTestRunner", | |||
| @@ -751,6 +752,8 @@ public class JUnitTask extends Task { | |||
| * @since Ant 1.2 | |||
| */ | |||
| public void execute() throws BuildException { | |||
| checkMethodLists(); | |||
| setupJUnitDelegate(); | |||
| List testLists = new ArrayList(); | |||
| @@ -851,6 +854,9 @@ public class JUnitTask extends Task { | |||
| while (iter.hasNext()) { | |||
| test = (JUnitTest) iter.next(); | |||
| printDual(writer, logWriter, test.getName()); | |||
| if (test.getMethods() != null) { | |||
| printDual(writer, logWriter, ":" + test.getMethodsString().replace(',', '+')); | |||
| } | |||
| if (test.getTodir() == null) { | |||
| printDual(writer, logWriter, | |||
| "," + getProject().resolveFile(".")); | |||
| @@ -922,6 +928,9 @@ public class JUnitTask extends Task { | |||
| cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner"); | |||
| if (casesFile == null) { | |||
| cmd.createArgument().setValue(test.getName()); | |||
| if (test.getMethods() != null) { | |||
| cmd.createArgument().setValue(Constants.METHOD_NAMES + test.getMethodsString()); | |||
| } | |||
| } else { | |||
| log("Running multiple tests in the same VM", Project.MSG_VERBOSE); | |||
| cmd.createArgument().setValue(Constants.TESTSFILE + casesFile); | |||
| @@ -1322,7 +1331,7 @@ public class JUnitTask extends Task { | |||
| if (classLoader != null) { | |||
| classLoader.setThreadContextLoader(); | |||
| } | |||
| runner = delegate.newJUnitTestRunner(test, test.getHaltonerror(), | |||
| runner = delegate.newJUnitTestRunner(test, test.getMethods(), test.getHaltonerror(), | |||
| test.getFiltertrace(), | |||
| test.getHaltonfailure(), false, | |||
| true, classLoader); | |||
| @@ -1407,6 +1416,29 @@ public class JUnitTask extends Task { | |||
| 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 enumeration | |||
| @@ -55,6 +55,7 @@ public interface JUnitTaskMirror { | |||
| /** | |||
| * Create a new test runner for a test. | |||
| * @param test the test to run. | |||
| * @param methods names of the test methods to be run. | |||
| * @param haltOnError if true halt the tests if an error occurs. | |||
| * @param filterTrace if true filter the stack traces. | |||
| * @param haltOnFailure if true halt the test if a failure occurs. | |||
| @@ -63,7 +64,7 @@ public interface JUnitTaskMirror { | |||
| * @param classLoader the classloader to use to create the runner. | |||
| * @return the test runner. | |||
| */ | |||
| JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, boolean haltOnError, | |||
| JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError, | |||
| boolean filterTrace, boolean haltOnFailure, boolean showOutput, | |||
| boolean logTestListenerEvents, AntClassLoader classLoader); | |||
| @@ -60,9 +60,10 @@ public final class JUnitTaskMirrorImpl implements JUnitTaskMirror { | |||
| /** {@inheritDoc}. */ | |||
| public JUnitTaskMirror.JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, | |||
| String[] methods, | |||
| boolean haltOnError, boolean filterTrace, boolean haltOnFailure, | |||
| boolean showOutput, boolean logTestListenerEvents, AntClassLoader classLoader) { | |||
| return new JUnitTestRunner(test, haltOnError, filterTrace, haltOnFailure, | |||
| return new JUnitTestRunner(test, methods, haltOnError, filterTrace, haltOnFailure, | |||
| showOutput, logTestListenerEvents, classLoader); | |||
| } | |||
| @@ -22,6 +22,7 @@ import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Properties; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.PropertyHelper; | |||
| @@ -41,6 +42,19 @@ public class JUnitTest extends BaseTest implements Cloneable { | |||
| /** the name of the test case */ | |||
| private String name = null; | |||
| /** | |||
| * whether the list of test methods has been specified | |||
| * @see #setMethods(java.lang.String) | |||
| * @see #setMethods(java.lang.String[]) | |||
| */ | |||
| private boolean methodsSpecified = false; | |||
| /** comma-separated list of names of test methods to execute */ | |||
| private String methodsList = null; | |||
| /** the names of test methods to execute */ | |||
| private String[] methods = null; | |||
| /** the name of the result file */ | |||
| private String outfile = null; | |||
| @@ -73,11 +87,53 @@ public class JUnitTest extends BaseTest implements Cloneable { | |||
| * @param filtertrace if true filter stack traces. | |||
| */ | |||
| public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure, | |||
| boolean filtertrace) { | |||
| boolean filtertrace) { | |||
| this(name, haltOnError, haltOnFailure, filtertrace, null); | |||
| } | |||
| /** | |||
| * Constructor with options. | |||
| * @param name the name of the test. | |||
| * @param haltOnError if true halt the tests if there is an error. | |||
| * @param haltOnFailure if true halt the tests if there is a failure. | |||
| * @param filtertrace if true filter stack traces. | |||
| * @param methods if true run only test methods that failed during the | |||
| * previous run of the test suite | |||
| * @since 1.8.2 | |||
| */ | |||
| public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure, | |||
| boolean filtertrace, String[] methods) { | |||
| this.name = name; | |||
| this.haltOnError = haltOnError; | |||
| this.haltOnFail = haltOnFailure; | |||
| this.filtertrace = filtertrace; | |||
| this.methods = methods; | |||
| this.methodsSpecified = (methods != null); | |||
| } | |||
| /** | |||
| * Sets names of individual test methods to be executed. | |||
| * @param value comma-separated list of names of individual test methods | |||
| * to be executed, | |||
| * or <code>null</code> if all test methods should be executed | |||
| * @since 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; | |||
| } | |||
| /** | |||
| * 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. | |||
| * @return the name of the test. | |||
| @@ -163,6 +163,9 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| */ | |||
| private static String crashFile = null; | |||
| /** Names of test methods to execute */ | |||
| private String[] methods = null; | |||
| /** | |||
| * Constructor for fork=true or when the user hasn't specified a | |||
| * classpath. | |||
| @@ -205,7 +208,26 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| public JUnitTestRunner(JUnitTest test, boolean haltOnError, | |||
| boolean filtertrace, boolean haltOnFailure, | |||
| boolean showOutput, boolean logTestListenerEvents) { | |||
| this(test, haltOnError, filtertrace, haltOnFailure, showOutput, | |||
| this(test, null, haltOnError, filtertrace, haltOnFailure, showOutput, | |||
| logTestListenerEvents, null); | |||
| } | |||
| /** | |||
| * Constructor for fork=true or when the user hasn't specified a | |||
| * classpath. | |||
| * @param test the test to run. | |||
| * @param methods names of methods of the test to be executed. | |||
| * @param haltOnError whether to stop the run if an error is found. | |||
| * @param filtertrace whether to filter junit.*.* stack frames out of exceptions | |||
| * @param haltOnFailure whether to stop the run if failure is found. | |||
| * @param showOutput whether to send output to System.out/.err as well as formatters. | |||
| * @param logTestListenerEvents whether to print TestListener events. | |||
| * @since 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); | |||
| } | |||
| @@ -254,12 +276,26 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| boolean filtertrace, boolean haltOnFailure, | |||
| boolean showOutput, boolean logTestListenerEvents, | |||
| ClassLoader loader) { | |||
| this(test, null, haltOnError, filtertrace, haltOnFailure, showOutput, | |||
| logTestListenerEvents, loader); | |||
| } | |||
| /** | |||
| * Constructor to use when the user has specified a classpath. | |||
| * @since 1.8.2 | |||
| */ | |||
| public JUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError, | |||
| boolean filtertrace, boolean haltOnFailure, | |||
| boolean showOutput, boolean logTestListenerEvents, | |||
| ClassLoader loader) { | |||
| JUnitTestRunner.filtertrace = filtertrace; | |||
| this.junitTest = test; | |||
| this.haltOnError = haltOnError; | |||
| this.haltOnFailure = haltOnFailure; | |||
| this.showOutput = showOutput; | |||
| this.logTestListenerEvents = logTestListenerEvents; | |||
| this.methods = methods; | |||
| this.loader = loader; | |||
| } | |||
| @@ -340,9 +376,12 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| loader); | |||
| } | |||
| final boolean testMethodsSpecified = (methods != null); | |||
| // check for a static suite method first, even when using | |||
| // JUnit 4 | |||
| Method suiteMethod = null; | |||
| if (!testMethodsSpecified) { | |||
| try { | |||
| // check if there is a suite method | |||
| suiteMethod = testClass.getMethod("suite", new Class[0]); | |||
| @@ -350,6 +389,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| // no appropriate suite method found. We don't report any | |||
| // error here since it might be perfectly normal. | |||
| } | |||
| } | |||
| if (suiteMethod != null) { | |||
| // if there is a suite method available, then try | |||
| @@ -359,7 +399,23 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| } else { | |||
| Class junit4TestAdapterClass = null; | |||
| boolean useSingleMethodAdapter = false; | |||
| if (junit.framework.TestCase.class.isAssignableFrom(testClass)) { | |||
| // Do not use JUnit 4 API for running JUnit 3.x | |||
| // tests - it is not able to run individual test | |||
| // methods. | |||
| // | |||
| // Technical details: | |||
| // org.junit.runner.Request.method(Class, String).getRunner() | |||
| // would return a runner which always executes all | |||
| // test methods. The reason is that the Runner would be | |||
| // an instance of class | |||
| // org.junit.internal.runners.OldTestClassRunner | |||
| // that does not implement interface Filterable - so it | |||
| // is unable to filter out test methods not matching | |||
| // the requested name. | |||
| } else { | |||
| // Check for JDK 5 first. Will *not* help on JDK 1.4 | |||
| // if only junit-4.0.jar in CP because in that case | |||
| // linkage of whole task will already have failed! But | |||
| @@ -373,29 +429,69 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| if (loader == null) { | |||
| junit4TestAdapterClass = | |||
| Class.forName(JUNIT_4_TEST_ADAPTER); | |||
| if (testMethodsSpecified) { | |||
| /* | |||
| * We cannot try to load the JUnit4TestAdapter | |||
| * before trying to load JUnit4TestMethodAdapter | |||
| * because it might fail with | |||
| * NoClassDefFoundException, instead of plain | |||
| * ClassNotFoundException. | |||
| */ | |||
| junit4TestAdapterClass = Class.forName( | |||
| "org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter"); | |||
| useSingleMethodAdapter = true; | |||
| } | |||
| } else { | |||
| junit4TestAdapterClass = | |||
| Class.forName(JUNIT_4_TEST_ADAPTER, | |||
| true, loader); | |||
| if (testMethodsSpecified) { | |||
| junit4TestAdapterClass = | |||
| Class.forName( | |||
| "org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter", | |||
| true, loader); | |||
| useSingleMethodAdapter = true; | |||
| } | |||
| } | |||
| } catch (ClassNotFoundException e) { | |||
| // OK, fall back to JUnit 3. | |||
| } | |||
| } | |||
| junit4 = junit4TestAdapterClass != null; | |||
| if (junit4) { | |||
| // Let's use it! | |||
| Class[] formalParams; | |||
| Object[] actualParams; | |||
| if (useSingleMethodAdapter) { | |||
| formalParams = new Class[] {Class.class, String[].class}; | |||
| actualParams = new Object[] {testClass, methods}; | |||
| } else { | |||
| formalParams = new Class[] {Class.class}; | |||
| actualParams = new Object[] {testClass}; | |||
| } | |||
| suite = | |||
| (Test) junit4TestAdapterClass | |||
| .getConstructor(new Class[] {Class.class}). | |||
| newInstance(new Object[] {testClass}); | |||
| .getConstructor(formalParams). | |||
| newInstance(actualParams); | |||
| } else { | |||
| // Use JUnit 3. | |||
| // try to extract a test suite automatically this | |||
| // will generate warnings if the class is no | |||
| // suitable Test | |||
| suite = new TestSuite(testClass); | |||
| if (!testMethodsSpecified) { | |||
| suite = new TestSuite(testClass); | |||
| } else if (methods.length == 1) { | |||
| suite = TestSuite.createTest(testClass, methods[0]); | |||
| } else { | |||
| TestSuite testSuite = new TestSuite(testClass.getName()); | |||
| for (int i = 0; i < methods.length; i++) { | |||
| testSuite.addTest( | |||
| TestSuite.createTest(testClass, methods[i])); | |||
| } | |||
| suite = testSuite; | |||
| } | |||
| } | |||
| } | |||
| @@ -670,11 +766,16 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| * <tr><td>logtestlistenerevents</td><td>log TestListener events to | |||
| * System.out.</td><td>false</td></tr> | |||
| * | |||
| * <tr><td>methods</td><td>Comma-separated list of names of individual | |||
| * test methods to execute. | |||
| * </td><td>null</td></tr> | |||
| * | |||
| * </table> | |||
| * @param args the command line arguments. | |||
| * @throws IOException on error. | |||
| */ | |||
| public static void main(String[] args) throws IOException { | |||
| String[] methods = null; | |||
| boolean haltError = false; | |||
| boolean haltFail = false; | |||
| boolean stackfilter = true; | |||
| @@ -696,7 +797,15 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| } | |||
| for (int i = 1; i < args.length; i++) { | |||
| if (args[i].startsWith(Constants.HALT_ON_ERROR)) { | |||
| if (args[i].startsWith(Constants.METHOD_NAMES)) { | |||
| try { | |||
| String methodsList = args[i].substring(Constants.METHOD_NAMES.length()); | |||
| methods = JUnitTest.parseTestMethodNamesList(methodsList); | |||
| } catch (IllegalArgumentException ex) { | |||
| System.err.println("Invalid specification of test method names: " + args[i]); | |||
| System.exit(ERRORS); | |||
| } | |||
| } else if (args[i].startsWith(Constants.HALT_ON_ERROR)) { | |||
| haltError = Project.toBoolean(args[i].substring(Constants.HALT_ON_ERROR.length())); | |||
| } else if (args[i].startsWith(Constants.HALT_ON_FAILURE)) { | |||
| haltFail = Project.toBoolean(args[i].substring(Constants.HALT_ON_FAILURE.length())); | |||
| @@ -744,18 +853,30 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| java.io.BufferedReader reader = | |||
| new java.io.BufferedReader(new java.io.FileReader(args[0])); | |||
| String testCaseName; | |||
| String[] testMethodNames; | |||
| int code = 0; | |||
| boolean errorOccurred = false; | |||
| boolean failureOccurred = false; | |||
| String line = null; | |||
| while ((line = reader.readLine()) != null) { | |||
| StringTokenizer st = new StringTokenizer(line, ","); | |||
| testCaseName = st.nextToken(); | |||
| String testListSpec = st.nextToken(); | |||
| int colonIndex = testListSpec.indexOf(':'); | |||
| if (colonIndex == -1) { | |||
| testCaseName = testListSpec; | |||
| testMethodNames = null; | |||
| } else { | |||
| testCaseName = testListSpec.substring(0, colonIndex); | |||
| testMethodNames = JUnitTest.parseTestMethodNamesList( | |||
| testListSpec | |||
| .substring(colonIndex + 1) | |||
| .replace('+', ',')); | |||
| } | |||
| JUnitTest t = new JUnitTest(testCaseName); | |||
| t.setTodir(new File(st.nextToken())); | |||
| t.setOutfile(st.nextToken()); | |||
| t.setProperties(props); | |||
| code = launch(t, haltError, stackfilter, haltFail, | |||
| code = launch(t, testMethodNames, haltError, stackfilter, haltFail, | |||
| showOut, outputToFormat, | |||
| logTestListenerEvents); | |||
| errorOccurred = (code == ERRORS); | |||
| @@ -783,7 +904,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| JUnitTest t = new JUnitTest(args[0]); | |||
| t.setProperties(props); | |||
| returnCode = launch( | |||
| t, haltError, stackfilter, haltFail, | |||
| t, methods, haltError, stackfilter, haltFail, | |||
| showOut, outputToFormat, logTestListenerEvents); | |||
| } | |||
| @@ -917,12 +1038,12 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||
| /** | |||
| * @since Ant 1.6.2 | |||
| */ | |||
| private static int launch(JUnitTest t, boolean haltError, | |||
| private static int launch(JUnitTest t, String[] methods, boolean haltError, | |||
| boolean stackfilter, boolean haltFail, | |||
| boolean showOut, boolean outputToFormat, | |||
| boolean logTestListenerEvents) { | |||
| JUnitTestRunner runner = | |||
| new JUnitTestRunner(t, haltError, stackfilter, haltFail, showOut, | |||
| new JUnitTestRunner(t, methods, haltError, stackfilter, haltFail, showOut, | |||
| logTestListenerEvents, null); | |||
| runner.forked = true; | |||
| runner.outputToFormatters = outputToFormat; | |||
| @@ -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); | |||
| } | |||
| // 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 | |||
| public void testNoSuite(){ | |||
| TestRunner runner = createRunner(NoSuiteTestCase.class); | |||
| @@ -87,14 +103,22 @@ public class JUnitTestRunnerTest extends TestCase { | |||
| } | |||
| protected TestRunner createRunner(Class clazz){ | |||
| return new TestRunner(new JUnitTest(clazz.getName()), true, true, true); | |||
| return new TestRunner(new JUnitTest(clazz.getName()), null, | |||
| true, true, true); | |||
| } | |||
| protected TestRunner createRunnerForTestMethod(Class clazz, String method){ | |||
| return new TestRunner(new JUnitTest(clazz.getName()), new String[] {method}, | |||
| true, true, true); | |||
| } | |||
| // the test runner that wrap the dummy formatter that interests us | |||
| private final static class TestRunner extends JUnitTestRunner { | |||
| private ResultFormatter formatter = new ResultFormatter(); | |||
| TestRunner(JUnitTest test, boolean haltonerror, boolean filtertrace, boolean haltonfailure){ | |||
| super(test, haltonerror, filtertrace, haltonfailure, TestRunner.class.getClassLoader()); | |||
| TestRunner(JUnitTest test, String[] methods, boolean haltonerror, | |||
| boolean filtertrace, boolean haltonfailure){ | |||
| super(test, methods, haltonerror, filtertrace, haltonfailure, | |||
| false, false, TestRunner.class.getClassLoader()); | |||
| // use the classloader that loaded this class otherwise | |||
| // it will not be able to run inner classes if this test | |||
| // is ran in non-forked mode. | |||
| @@ -133,6 +157,24 @@ public class JUnitTestRunnerTest extends TestCase { | |||
| public static class NoTestCase { | |||
| } | |||
| public static class InvalidMethodTestCase extends TestCase { | |||
| public InvalidMethodTestCase(String name){ super(name); } | |||
| public void testA(){ | |||
| throw new NullPointerException("thrown on purpose"); | |||
| } | |||
| } | |||
| public static class ValidMethodTestCase extends TestCase { | |||
| public ValidMethodTestCase(String name){ super(name); } | |||
| public void testA(){ | |||
| // expected to be executed | |||
| } | |||
| public void testB(){ | |||
| // should not be executed | |||
| throw new NullPointerException("thrown on purpose"); | |||
| } | |||
| } | |||
| public static class InvalidTestCase extends TestCase { | |||
| public InvalidTestCase(String name){ | |||
| super(name); | |||