Categories:
Audio (13)
Biotech (29)
Bytecode (36)
Database (77)
Framework (7)
Game (7)
General (507)
Graphics (53)
I/O (35)
IDE (2)
JAR Tools (101)
JavaBeans (21)
JDBC (121)
JDK (426)
JSP (20)
Logging (108)
Mail (58)
Messaging (8)
Network (84)
PDF (97)
Report (7)
Scripting (84)
Security (32)
Server (121)
Servlet (26)
SOAP (24)
Testing (54)
Web (15)
XML (309)
Collections:
Other Resources:
Apache Ant Source Code Files
Apache Ant Source Code Files are inside the Apache Ant source package file like apache-ant-1.10.10-src.zip. Unzip the source package file and go to the "src/main" sub-directory, you will see source code files.
Here is the list of Java source code files of the Apache Ant 1.10.10 in \Users\fyicenter\apache-ant-1.10.10\src\main:
✍: FYIcenter.com
⏎ org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
/* * 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 * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.tools.ant.taskdefs.optional.junit; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.lang.reflect.Constructor; import java.net.URL; import java.nio.file.Files; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Vector; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.MagicNames; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Execute; import org.apache.tools.ant.taskdefs.ExecuteWatchdog; import org.apache.tools.ant.taskdefs.LogOutputStream; import org.apache.tools.ant.taskdefs.PumpStreamHandler; import org.apache.tools.ant.types.Assertions; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.CommandlineJava; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.Environment; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Permissions; import org.apache.tools.ant.types.PropertySet; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.LoaderUtils; import org.apache.tools.ant.util.SplitClassLoader; import org.apache.tools.ant.util.StringUtils; /** * Runs JUnit tests. * * <p>JUnit is a framework to create unit tests. It has been initially * created by Erich Gamma and Kent Beck. JUnit can be found at <a * href="https://www.junit.org">https://www.junit.org</a>. * * <p><code>JUnitTask</code> can run a single specific * <code>JUnitTest</code> using the <code>test</code> element.</p> * For example, the following target <pre> * <target name="test-int-chars" depends="jar-test"> * <echo message="testing international characters"/> * <junit printsummary="no" haltonfailure="yes" fork="false"> * <classpath refid="classpath"/> * <formatter type="plain" usefile="false" /> * <test name="org.apache.ecs.InternationalCharTest" /> * </junit> * </target> * </pre> * <p>runs a single junit test * (<code>org.apache.ecs.InternationalCharTest</code>) in the current * VM using the path with id <code>classpath</code> as classpath and * presents the results formatted using the standard * <code>plain</code> formatter on the command line.</p> * * <p>This task can also run batches of tests. The * <code>batchtest</code> element creates a <code>BatchTest</code> * based on a fileset. This allows, for example, all classes found in * directory to be run as testcases.</p> * * <p>For example,</p><pre> * <target name="run-tests" depends="dump-info,compile-tests" if="junit.present"> * <junit printsummary="no" haltonfailure="yes" fork="${junit.fork}"> * <jvmarg value="-classic"/> * <classpath refid="tests-classpath"/> * <sysproperty key="build.tests.value" value="${build.tests.value}"/> * <formatter type="brief" usefile="false" /> * <batchtest> * <fileset dir="${tests.dir}"> * <include name="**/*Test*" /> * </fileset> * </batchtest> * </junit> * </target> * </pre> * <p>this target finds any classes with a <code>test</code> directory * anywhere in their path (under the top <code>${tests.dir}</code>, of * course) and creates <code>JUnitTest</code>'s for each one.</p> * * <p>Of course, <code><junit></code> and * <code><batch></code> elements can be combined for more * complex tests. For an example, see the ant <code>build.xml</code> * target <code>run-tests</code> (the second example is an edited * version).</p> * * <p>To spawn a new Java VM to prevent interferences between * different testcases, you need to enable <code>fork</code>. A * number of attributes and elements allow you to set up how this JVM * runs. * * * @since Ant 1.2 * * @see JUnitTest * @see BatchTest */ public class JUnitTask extends Task { private static final String CLASSPATH = "CLASSPATH"; private static final int STRING_BUFFER_SIZE = 128; /** * @since Ant 1.7 */ public static final String TESTLISTENER_PREFIX = "junit.framework.TestListener: "; /** * Name of magic property that enables test listener events. */ public static final String ENABLE_TESTLISTENER_EVENTS = "ant.junit.enabletestlistenerevents"; private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); private CommandlineJava commandline; private final List<JUnitTest> tests = new Vector<>(); private final List<BatchTest> batchTests = new Vector<>(); private final Vector<FormatterElement> formatters = new Vector<>(); private File dir = null; private Integer timeout = null; private boolean summary = false; private boolean reloading = true; private String summaryValue = ""; private JUnitTaskMirror.JUnitTestRunnerMirror runner = null; private boolean newEnvironment = false; private final Environment env = new Environment(); private boolean includeAntRuntime = true; private Path antRuntimeClasses = null; // Do we send output to System.out/.err in addition to the formatters? private boolean showOutput = false; // Do we send output to the formatters ? private boolean outputToFormatters = true; private boolean logFailedTests = true; private File tmpDir; private AntClassLoader classLoader = null; private Permissions perm = null; private ForkMode forkMode = new ForkMode("perTest"); private boolean splitJUnit = false; private boolean enableTestListenerEvents = false; private JUnitTaskMirror delegate; private ClassLoader mirrorLoader; /** A boolean on whether to get the forked path for ant classes */ private boolean forkedPathChecked = false; /* set when a test fails/errs with haltonfailure/haltonerror and >1 thread to stop other threads */ private volatile BuildException caughtBuildException = null; // Attributes for basetest private boolean haltOnError = false; private boolean haltOnFail = false; private boolean filterTrace = true; private boolean fork = false; private int threads = 1; private String failureProperty; private String errorProperty; /** * If true, force ant to re-classload all classes for each JUnit TestCase * * @param value force class reloading for each test case */ public void setReloading(final boolean value) { reloading = value; } /** * If true, smartly filter the stack frames of * JUnit errors and failures before reporting them. * * <p>This property is applied on all BatchTest (batchtest) and * JUnitTest (test) however it can possibly be overridden by their * own properties.</p> * @param value <code>false</code> if it should not filter, otherwise * <code>true</code> * * @since Ant 1.5 */ public void setFiltertrace(final boolean value) { this.filterTrace = value; } /** * If true, stop the build process when there is an error in a test. * This property is applied on all BatchTest (batchtest) and JUnitTest * (test) however it can possibly be overridden by their own * properties. * @param value <code>true</code> if it should halt, otherwise * <code>false</code> * * @since Ant 1.2 */ public void setHaltonerror(final boolean value) { this.haltOnError = value; } /** * Property to set to "true" if there is a error in a test. * * <p>This property is applied on all BatchTest (batchtest) and * JUnitTest (test), however, it can possibly be overridden by * their own properties.</p> * @param propertyName the name of the property to set in the * event of an error. * * @since Ant 1.4 */ public void setErrorProperty(final String propertyName) { this.errorProperty = propertyName; } /** * If true, stop the build process if a test fails * (errors are considered failures as well). * This property is applied on all BatchTest (batchtest) and * JUnitTest (test) however it can possibly be overridden by their * own properties. * @param value <code>true</code> if it should halt, otherwise * <code>false</code> * * @since Ant 1.2 */ public void setHaltonfailure(final boolean value) { this.haltOnFail = value; } /** * Property to set to "true" if there is a failure in a test. * * <p>This property is applied on all BatchTest (batchtest) and * JUnitTest (test), however, it can possibly be overridden by * their own properties.</p> * @param propertyName the name of the property to set in the * event of an failure. * * @since Ant 1.4 */ public void setFailureProperty(final String propertyName) { this.failureProperty = propertyName; } /** * If true, JVM should be forked for each test. * * <p>It avoids interference between testcases and possibly avoids * hanging the build. this property is applied on all BatchTest * (batchtest) and JUnitTest (test) however it can possibly be * overridden by their own properties.</p> * @param value <code>true</code> if a JVM should be forked, otherwise * <code>false</code> * @see #setTimeout * * @since Ant 1.2 */ public void setFork(final boolean value) { this.fork = value; } /** * Set the behavior when {@link #setFork fork} fork has been enabled. * * <p>Possible values are "once", "perTest" and "perBatch". If * set to "once", only a single Java VM will be forked for all * tests, with "perTest" (the default) each test will run in a * fresh Java VM and "perBatch" will run all tests from the same * <batchtest> in the same Java VM.</p> * * <p>This attribute will be ignored if tests run in the same VM * as Ant.</p> * * <p>Only tests with the same configuration of haltonerror, * haltonfailure, errorproperty, failureproperty and filtertrace * can share a forked Java VM, so even if you set the value to * "once", Ant may need to fork multiple VMs.</p> * @param mode the mode to use. * @since Ant 1.6.2 */ public void setForkMode(final ForkMode mode) { this.forkMode = mode; } /** * Set the number of test threads to be used for parallel test * execution. The default is 1, which is the same behavior as * before parallel test execution was possible. * * <p>This attribute will be ignored if tests run in the same VM * as Ant.</p> * * @param threads int * @since Ant 1.9.4 */ public void setThreads(final int threads) { if (threads >= 0) { this.threads = threads; } } /** * If true, print one-line statistics for each test, or "withOutAndErr" * to also show standard output and error. * * Can take the values on, off, and withOutAndErr. * * @param value <code>true</code> to print a summary, * <code>withOutAndErr</code> to include the test's output as * well, <code>false</code> otherwise. * @see SummaryJUnitResultFormatter * @since Ant 1.2 */ public void setPrintsummary(final SummaryAttribute value) { summaryValue = value.getValue(); summary = value.asBoolean(); } /** * Print summary enumeration values. */ public static class SummaryAttribute extends EnumeratedAttribute { /** * list the possible values * @return array of allowed values */ @Override public String[] getValues() { return new String[] {"true", "yes", "false", "no", "on", "off", "withOutAndErr"}; } /** * gives the boolean equivalent of the authorized values * @return boolean equivalent of the value */ public boolean asBoolean() { final String v = getValue(); return "true".equals(v) || "on".equals(v) || "yes".equals(v) || "withOutAndErr".equals(v); } } /** * Set the timeout value (in milliseconds). * * <p>If the test is running for more than this value, the test * will be canceled. (works only when in 'fork' mode).</p> * * @param value the maximum time (in milliseconds) allowed before * declaring the test as 'timed-out' * @see #setFork(boolean) * @since Ant 1.2 */ public void setTimeout(final Integer value) { timeout = value; } /** * Set the maximum memory to be used by all forked JVMs. * * @param max the value as defined by <code>-mx</code> or <code>-Xmx</code> * in the java command line options. * @since Ant 1.2 */ public void setMaxmemory(final String max) { getCommandline().setMaxmemory(max); } /** * The command used to invoke the Java Virtual Machine, * default is 'java'. The command is resolved by * java.lang.Runtime.exec(). Ignored if fork is disabled. * * @param value the new VM to use instead of <code>java</code> * @see #setFork(boolean) * * @since Ant 1.2 */ public void setJvm(final String value) { getCommandline().setVm(value); } /** * Adds a JVM argument; ignored if not forking. * * @return create a new JVM argument so that any argument can be * passed to the JVM. * @see #setFork(boolean) * @since Ant 1.2 */ public Commandline.Argument createJvmarg() { return getCommandline().createVmArgument(); } /** * The directory to invoke the VM in. Ignored if no JVM is forked. * * @param dir the directory to invoke the JVM from. * @see #setFork(boolean) * @since Ant 1.2 */ public void setDir(final File dir) { this.dir = dir; } /** * Adds a system property that tests can access. * This might be useful to transfer Ant properties to the * testcases when JVM forking is not enabled. * * @since Ant 1.3 * @deprecated since Ant 1.6 * @param sysp environment variable to add */ @Deprecated public void addSysproperty(final Environment.Variable sysp) { getCommandline().addSysproperty(sysp); } /** * Adds a system property that tests can access. * This might be useful to transfer Ant properties to the * testcases when JVM forking is not enabled. * * @param sysp new environment variable to add * @since Ant 1.6 */ public void addConfiguredSysproperty(final Environment.Variable sysp) { // get a build exception if there is a missing key or value // see bugzilla report 21684 final String testString = sysp.getContent(); getProject().log("sysproperty added : " + testString, Project.MSG_DEBUG); getCommandline().addSysproperty(sysp); } /** * Adds a set of properties that will be used as system properties * that tests can access. * * <p>This might be useful to transfer Ant properties to the * testcases when JVM forking is not enabled.</p> * * @param sysp set of properties to be added * @since Ant 1.6 */ public void addSyspropertyset(final PropertySet sysp) { getCommandline().addSyspropertyset(sysp); } /** * Adds path to classpath used for tests. * * @return reference to the classpath in the embedded java command line * @since Ant 1.2 */ public Path createClasspath() { return getCommandline().createClasspath(getProject()).createPath(); } /** * Adds a path to the bootclasspath. * * @return reference to the bootclasspath in the embedded java command line * @since Ant 1.6 */ public Path createBootclasspath() { return getCommandline().createBootclasspath(getProject()).createPath(); } /** * Add a path to the modulepath. * * @return created modulepath. * @since 1.9.8 */ public Path createModulepath() { return getCommandline().createModulepath(getProject()).createPath(); } /** * Add a path to the upgrademodulepath. * * @return created upgrademodulepath. * @since 1.9.8 */ public Path createUpgrademodulepath() { return getCommandline().createUpgrademodulepath(getProject()).createPath(); } /** * Adds an environment variable; used when forking. * * <p>Will be ignored if we are not forking a new VM.</p> * * @param var environment variable to be added * @since Ant 1.5 */ public void addEnv(final Environment.Variable var) { env.addVariable(var); } /** * If true, use a new environment when forked. * * <p>Will be ignored if we are not forking a new VM.</p> * * @param newenv boolean indicating if setting a new environment is wished * @since Ant 1.5 */ public void setNewenvironment(final boolean newenv) { newEnvironment = newenv; } /** * Preset the attributes of the test * before configuration in the build * script. * This allows attributes in the <junit> task * be be defaults for the tests, but allows * individual tests to override the defaults. * * @param test BaseTest */ private void preConfigure(final BaseTest test) { test.setFiltertrace(filterTrace); test.setHaltonerror(haltOnError); if (errorProperty != null) { test.setErrorProperty(errorProperty); } test.setHaltonfailure(haltOnFail); if (failureProperty != null) { test.setFailureProperty(failureProperty); } test.setFork(fork); } /** * Add a new single testcase. * @param test a new single testcase * @see JUnitTest * @since Ant 1.2 */ public void addTest(final JUnitTest test) { tests.add(test); preConfigure(test); } /** * Adds a set of tests based on pattern matching. * * @return a new instance of a batch test. * @see BatchTest * @since Ant 1.2 */ public BatchTest createBatchTest() { final BatchTest test = new BatchTest(getProject()); batchTests.add(test); preConfigure(test); return test; } /** * Add a new formatter to all tests of this task. * * @param fe formatter element * @since Ant 1.2 */ public void addFormatter(final FormatterElement fe) { formatters.add(fe); } /** * If true, include ant.jar, optional.jar and junit.jar in the forked VM. * * @param b include ant run time yes or no * @since Ant 1.5 */ public void setIncludeantruntime(final boolean b) { includeAntRuntime = b; } /** * If true, send any output generated by tests to Ant's logging system * as well as to the formatters. * By default only the formatters receive the output. * * <p>Output will always be passed to the formatters and not by * shown by default. This option should for example be set for * tests that are interactive and prompt the user to do * something.</p> * * @param showOutput if true, send output to Ant's logging system too * @since Ant 1.5 */ public void setShowOutput(final boolean showOutput) { this.showOutput = showOutput; } /** * If true, send any output generated by tests to the formatters. * * @param outputToFormatters if true, send output to formatters (Default * is true). * @since Ant 1.7.0 */ public void setOutputToFormatters(final boolean outputToFormatters) { this.outputToFormatters = outputToFormatters; } /** * If true, write a single "FAILED" line for failed tests to Ant's * log system. * * @param logFailedTests boolean * @since Ant 1.8.0 */ public void setLogFailedTests(final boolean logFailedTests) { this.logFailedTests = logFailedTests; } /** * Assertions to enable in this program (if fork=true) * * @since Ant 1.6 * @param asserts assertion set */ public void addAssertions(final Assertions asserts) { if (getCommandline().getAssertions() != null) { throw new BuildException("Only one assertion declaration is allowed"); } getCommandline().setAssertions(asserts); } /** * Sets the permissions for the application run inside the same JVM. * * @since Ant 1.6 * @return Permissions */ public Permissions createPermissions() { if (perm == null) { perm = new Permissions(); } return perm; } /** * If set, system properties will be copied to the cloned VM - as * well as the bootclasspath unless you have explicitly specified * a bootclasspath. * * <p>Doesn't have any effect unless fork is true.</p> * * @param cloneVm a <code>boolean</code> value. * @since Ant 1.7 */ public void setCloneVm(final boolean cloneVm) { getCommandline().setCloneVm(cloneVm); } /** * Creates a new JUnitRunner and enables fork of a new Java VM. * * @throws Exception never * @since Ant 1.2 */ public JUnitTask() throws Exception { //NOSONAR } /** * Where Ant should place temporary files. * * @param tmpDir location where temporary files should go to * @since Ant 1.6 */ public void setTempdir(final File tmpDir) { if (tmpDir != null && (!tmpDir.exists() || !tmpDir.isDirectory())) { throw new BuildException("%s is not a valid temp directory", tmpDir); } this.tmpDir = tmpDir; } /** * Whether test listener events shall be generated. * * <p>Defaults to false.</p> * * <p>This value will be overridden by the magic property * ant.junit.enabletestlistenerevents if it has been set.</p> * * @param b boolean * @since Ant 1.8.2 */ public void setEnableTestListenerEvents(final boolean b) { enableTestListenerEvents = b; } /** * Whether test listener events shall be generated. * * @return boolean * @since Ant 1.8.2 */ public boolean getEnableTestListenerEvents() { final String e = getProject().getProperty(ENABLE_TESTLISTENER_EVENTS); if (e != null) { return Project.toBoolean(e); } return enableTestListenerEvents; } /** * Adds the jars or directories containing Ant, this task and * JUnit to the classpath - this should make the forked JVM work * without having to specify them directly. * * @since Ant 1.4 */ @Override public void init() { antRuntimeClasses = new Path(getProject()); splitJUnit = !addClasspathResource("/junit/framework/TestCase.class"); addClasspathEntry("/org/apache/tools/ant/launch/AntMain.class"); addClasspathEntry("/org/apache/tools/ant/Task.class"); addClasspathEntry("/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.class"); addClasspathEntry("/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.class"); } private static JUnitTaskMirror createMirror(final JUnitTask task, final ClassLoader loader) { try { loader.loadClass("junit.framework.Test"); // sanity check } catch (final ClassNotFoundException e) { throw new BuildException( "The <classpath> or <modulepath> for <junit> must include junit.jar " + "if not in Ant's own classpath", e, task.getLocation()); } try { final Class<? extends JUnitTaskMirror> c = loader.loadClass(JUnitTaskMirror.class.getName() + "Impl").asSubclass(JUnitTaskMirror.class); if (c.getClassLoader() != loader) { throw new BuildException("Overdelegating loader", task.getLocation()); } final Constructor<? extends JUnitTaskMirror> cons = c.getConstructor(JUnitTask.class); return cons.newInstance(task); } catch (final Exception e) { throw new BuildException(e, task.getLocation()); } } /** * Sets up the delegate that will actually run the tests. * * <p>Will be invoked implicitly once the delegate is needed.</p> * * @since Ant 1.7.1 */ protected void setupJUnitDelegate() { final ClassLoader myLoader = JUnitTask.class.getClassLoader(); if (splitJUnit) { final Path path = new Path(getProject()); path.add(antRuntimeClasses); Path extra = getCommandline().getClasspath(); if (extra != null) { path.add(extra); } extra = getCommandline().getModulepath(); if (extra != null && !hasJunit(path)) { path.add(expandModulePath(extra)); } mirrorLoader = AccessController.doPrivileged( (PrivilegedAction<ClassLoader>) () -> new SplitClassLoader( myLoader, path, getProject(), new String[] {"BriefJUnitResultFormatter", "JUnit4TestMethodAdapter", "JUnitResultFormatter", "JUnitTaskMirrorImpl", "JUnitTestRunner", "JUnitVersionHelper", "OutErrSummaryJUnitResultFormatter", "PlainJUnitResultFormatter", "SummaryJUnitResultFormatter", "TearDownOnVmCrash", "XMLJUnitResultFormatter", "IgnoredTestListener", "IgnoredTestResult", "CustomJUnit4TestAdapterCache", "TestListenerWrapper"})); } else { mirrorLoader = myLoader; } delegate = createMirror(this, mirrorLoader); } /** * Runs the testcase. * * @throws BuildException in case of test failures or errors * @since Ant 1.2 */ @Override public void execute() throws BuildException { checkMethodLists(); checkModules(); setupJUnitDelegate(); final List<List<JUnitTest>> testLists = new ArrayList<>(); /* parallel test execution is only supported for multi-process execution */ final int threads = !fork || forkMode.getValue().equals(ForkMode.ONCE) ? 1 : this.threads; final boolean forkPerTest = ForkMode.PER_TEST.equals(forkMode.getValue()); if (forkPerTest || ForkMode.ONCE.equals(forkMode.getValue())) { testLists.addAll(executeOrQueue(getIndividualTests(), forkPerTest)); } else { /* forkMode.getValue().equals(ForkMode.PER_BATCH) */ batchTests.stream().map(b -> executeOrQueue(b.elements(), false)) .forEach(testLists::addAll); testLists.addAll( executeOrQueue(Collections.enumeration(tests), forkPerTest)); } try { /* prior to parallel the code in 'oneJunitThread' used to be here. */ runTestsInThreads(testLists, threads); } finally { cleanup(); } } /* * When the list of tests is established, an array of threads is created to pick the * tests off the list one at a time and execute them until the list is empty. Tests are * not assigned to threads until the thread is available. * * This class is the runnable thread subroutine that takes care of passing the shared * list iterator and the handle back to the main class to the test execution subroutine * code 'runTestsInThreads'. One object is created for each thread and each one gets * a unique thread id that can be useful for tracing test starts and stops. * * Because the threads are picking tests off the same list, it is the list *iterator* * that must be shared, not the list itself - and the iterator must have a thread-safe * ability to pop the list - hence the synchronized 'getNextTest'. */ private class JunitTestThread implements Runnable { JunitTestThread(final JUnitTask master, final Iterator<List<JUnitTest>> iterator, final int id) { this.masterTask = master; this.iterator = iterator; this.id = id; } @Override public void run() { try { masterTask.oneJunitThread(iterator, id); } catch (final BuildException b) { /* saved to rethrow in main thread to be like single-threaded case */ caughtBuildException = b; } } private final JUnitTask masterTask; private final Iterator<List<JUnitTest>> iterator; private final int id; } /* * Because the threads are picking tests off the same list, it is the list *iterator* * that must be shared, not the list itself - and the iterator must have a thread-safe * ability to pop the list - hence the synchronized 'getNextTest'. We can't have two * threads get the same test, or two threads simultaneously pop the list so that a test * gets skipped! */ private List<JUnitTest> getNextTest(final Iterator<List<JUnitTest>> iter) { synchronized (iter) { if (iter.hasNext()) { return iter.next(); } return null; } } /* * This code loops keeps executing the next test or test bunch (depending on fork mode) * on the list of test cases until none are left. Basically this body of code used to * be in the execute routine above; now, several copies (one for each test thread) execute * simultaneously. The while loop was modified to call the new thread-safe atomic list * popping subroutine and the logging messages were added. * * If one thread aborts due to a BuildException (haltOnError, haltOnFailure, or any other * fatal reason, no new tests/batches will be started but the running threads will be * permitted to complete. Additional tests may start in already-running batch-test threads. */ private void oneJunitThread(final Iterator<List<JUnitTest>> iter, final int threadId) { List<JUnitTest> l; log("Starting test thread " + threadId, Project.MSG_VERBOSE); while ((caughtBuildException == null) && ((l = getNextTest(iter)) != null)) { log("Running test " + l.get(0).toString() + "(" + l.size() + ") in thread " + threadId, Project.MSG_VERBOSE); if (l.size() == 1) { execute(l.get(0), threadId); } else { execute(l, threadId); } } log("Ending test thread " + threadId, Project.MSG_VERBOSE); } private void runTestsInThreads(final List<List<JUnitTest>> testList, final int numThreads) { Iterator<List<JUnitTest>> iter = testList.iterator(); if (numThreads == 1) { /* with just one thread just run the test - don't create any threads */ oneJunitThread(iter, 0); } else { final Thread[] threads = new Thread[numThreads]; int i; boolean exceptionOccurred; /* Need to split apart tests, which are still grouped in batches */ /* is there a simpler Java mechanism to do this? */ /* I assume we don't want to do this with "per batch" forking. */ List<List<JUnitTest>> newlist = new ArrayList<>(); if (forkMode.getValue().equals(ForkMode.PER_TEST)) { for (List<JUnitTest> list : testList) { if (list.size() == 1) { newlist.add(list); } else { for (JUnitTest test : list) { newlist.add(Collections.singletonList(test)); } } } } else { newlist = testList; } iter = newlist.iterator(); /* create 1 thread using the passthrough class, and let each thread start */ for (i = 0; i < numThreads; i++) { threads[i] = new Thread(new JunitTestThread(this, iter, i + 1)); threads[i].start(); } /* wait for all of the threads to complete. Not sure if the exception can actually occur in this use case. */ do { exceptionOccurred = false; try { for (i = 0; i < numThreads; i++) { threads[i].join(); } } catch (final InterruptedException e) { exceptionOccurred = true; } } while (exceptionOccurred); /* an exception occurred in one of the threads - usually a haltOnError/Failure. throw the exception again so it behaves like the single-thread case */ if (caughtBuildException != null) { throw new BuildException(caughtBuildException); } /* all threads are completed - that's all there is to do. */ /* control will flow back to the test cleanup call and then execute is done. */ } } /** * Run the tests. * @param arg one JUnitTest * @param thread Identifies which thread is test running in (0 for single-threaded runs) * @throws BuildException in case of test failures or errors */ protected void execute(final JUnitTest arg, final int thread) throws BuildException { validateTestName(arg.getName()); final JUnitTest test = (JUnitTest) arg.clone(); test.setThread(thread); // set the default values if not specified //@todo should be moved to the test class instead. if (test.getTodir() == null) { test.setTodir(getProject().resolveFile(".")); } if (test.getOutfile() == null) { test.setOutfile("TEST-" + test.getName()); } // execute the test and get the return code TestResultHolder result; if (test.getFork()) { final ExecuteWatchdog watchdog = createWatchdog(); result = executeAsForked(test, watchdog, null); // null watchdog means no timeout, you'd better not check with null } else { result = executeInVM(test); } actOnTestResult(result, test, "Test " + test.getName()); } /** * Run the tests. * @param arg one JUnitTest * @throws BuildException in case of test failures or errors */ protected void execute(final JUnitTest arg) throws BuildException { execute(arg, 0); } /** * Throws a <code>BuildException</code> if the given test name is invalid. * Validity is defined as not <code>null</code>, not empty, and not the * string "null". * @param testName the test name to be validated * @throws BuildException if <code>testName</code> is not a valid test name */ private void validateTestName(final String testName) throws BuildException { if (testName == null || testName.isEmpty() || "null".equals(testName)) { throw new BuildException("test name must be specified"); } } /** * Execute a list of tests in a single forked Java VM. * @param testList the list of tests to execute. * @param thread Identifies which thread is test running in (0 for single-threaded runs) * @throws BuildException on error. */ protected void execute(final List<JUnitTest> testList, final int thread) throws BuildException { // Create a temporary file to pass the test cases to run to // the runner (one test case per line) final File casesFile = createTempPropertiesFile("junittestcases"); try (BufferedWriter writer = new BufferedWriter(new FileWriter(casesFile))) { log("Creating casesfile '" + casesFile.getAbsolutePath() + "' with content: ", Project.MSG_VERBOSE); final PrintStream logWriter = new PrintStream(new LogOutputStream(this, Project.MSG_VERBOSE)); JUnitTest test = null; for (JUnitTest t : testList) { test = t; test.setThread(thread); printDual(writer, logWriter, test.getName()); if (test.getMethods() != null) { printDual(writer, logWriter, ":" + test.getMethodsString().replace(',', '+')); } if (test.getTodir() == null) { printDual(writer, logWriter, "," + getProject().resolveFile(".")); } else { printDual(writer, logWriter, "," + test.getTodir()); } if (test.getOutfile() == null) { printlnDual(writer, logWriter, "," + "TEST-" + test.getName()); } else { printlnDual(writer, logWriter, "," + test.getOutfile()); } } writer.flush(); // execute the test and get the return code final ExecuteWatchdog watchdog = createWatchdog(); final TestResultHolder result = executeAsForked(test, watchdog, casesFile); actOnTestResult(result, test, "Tests"); } catch (final IOException e) { log(e.toString(), Project.MSG_ERR); throw new BuildException(e); } finally { try { FILE_UTILS.tryHardToDelete(casesFile); } catch (final Exception e) { log(e.toString(), Project.MSG_ERR); } } } /** * Execute a list of tests in a single forked Java VM. * @param testList the list of tests to execute. * @throws BuildException on error. */ protected void execute(final List<JUnitTest> testList) throws BuildException { execute(testList, 0); } /** * Execute a testcase by forking a new JVM. The command will block * until it finishes. To know if the process was destroyed or not * or whether the forked Java VM exited abnormally, use the * attributes of the returned holder object. * @param test the testcase to execute. * @param watchdog the watchdog in charge of cancelling the test if it * exceeds a certain amount of time. Can be <code>null</code>, in this case * the test could probably hang forever. * @param casesFile list of test cases to execute. Can be <code>null</code>, * in this case only one test is executed. * @return the test results from the JVM itself. * @throws BuildException in case of error creating a temporary property file, * or if the junit process can not be forked */ private TestResultHolder executeAsForked(JUnitTest test, final ExecuteWatchdog watchdog, final File casesFile) throws BuildException { if (perm != null) { log("Permissions ignored when running in forked mode!", Project.MSG_WARN); } CommandlineJava cmd; try { cmd = (CommandlineJava) getCommandline().clone(); } catch (final CloneNotSupportedException e) { throw new BuildException("This shouldn't happen", e, getLocation()); } 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); } cmd.createArgument().setValue(Constants.SKIP_NON_TESTS + String.valueOf(test.isSkipNonTests())); cmd.createArgument().setValue(Constants.FILTERTRACE + test.getFiltertrace()); cmd.createArgument().setValue(Constants.HALT_ON_ERROR + test.getHaltonerror()); cmd.createArgument().setValue(Constants.HALT_ON_FAILURE + test.getHaltonfailure()); checkIncludeAntRuntime(cmd); checkIncludeSummary(cmd); cmd.createArgument().setValue(Constants.SHOWOUTPUT + String.valueOf(showOutput)); cmd.createArgument().setValue(Constants.OUTPUT_TO_FORMATTERS + String.valueOf(outputToFormatters)); cmd.createArgument().setValue(Constants.LOG_FAILED_TESTS + String.valueOf(logFailedTests)); cmd.createArgument().setValue(Constants.THREADID + String.valueOf(test.getThread())); // #31885 cmd.createArgument().setValue(Constants.LOGTESTLISTENEREVENTS + String.valueOf(getEnableTestListenerEvents())); StringBuilder formatterArg = new StringBuilder(STRING_BUFFER_SIZE); final FormatterElement[] feArray = mergeFormatters(test); for (final FormatterElement fe : feArray) { if (fe.shouldUse(this)) { formatterArg.append(Constants.FORMATTER); formatterArg.append(fe.getClassname()); final File outFile = getOutput(fe, test); if (outFile != null) { formatterArg.append(","); formatterArg.append(outFile); } cmd.createArgument().setValue(formatterArg.toString()); formatterArg = new StringBuilder(); } } final File vmWatcher = createTempPropertiesFile("junitvmwatcher"); cmd.createArgument().setValue(Constants.CRASHFILE + vmWatcher.getAbsolutePath()); final File propsFile = createTempPropertiesFile("junit"); cmd.createArgument().setValue(Constants.PROPSFILE + propsFile.getAbsolutePath()); final Hashtable<String, Object> p = getProject().getProperties(); final Properties props = new Properties(); p.forEach(props::put); try { final OutputStream outstream = Files.newOutputStream(propsFile.toPath()); props.store(outstream, "Ant JUnitTask generated properties file"); outstream.close(); } catch (final IOException e) { FILE_UTILS.tryHardToDelete(propsFile); throw new BuildException("Error creating temporary properties " + "file.", e, getLocation()); } final Execute execute = new Execute( new JUnitLogStreamHandler( this, Project.MSG_INFO, Project.MSG_WARN), watchdog); execute.setCommandline(cmd.getCommandline()); execute.setAntRun(getProject()); if (dir != null) { execute.setWorkingDirectory(dir); } final String[] environment = env.getVariables(); if (environment != null) { for (String variable : environment) { log("Setting environment variable: " + variable, Project.MSG_VERBOSE); } } execute.setNewenvironment(newEnvironment); execute.setEnvironment(environment); log(cmd.describeCommand(), Project.MSG_VERBOSE); checkForkedPath(cmd); final TestResultHolder result = new TestResultHolder(); boolean success = false; try { result.exitCode = execute.execute(); success = true; } catch (final IOException e) { throw new BuildException("Process fork failed.", e, getLocation()); } finally { String vmCrashString = "unknown"; BufferedReader br = null; try { if (vmWatcher.exists()) { br = new BufferedReader(new FileReader(vmWatcher)); vmCrashString = br.readLine(); } else { vmCrashString = "Monitor file (" + vmWatcher.getAbsolutePath() + ") missing, location not writable," + " testcase not started or mixing ant versions?"; } } catch (final Exception e) { log(StringUtils.getStackTrace(e), Project.MSG_INFO); // ignored. } finally { FileUtils.close(br); if (vmWatcher.exists()) { FILE_UTILS.tryHardToDelete(vmWatcher); } } final boolean crash = (watchdog != null && watchdog.killedProcess()) || !Constants.TERMINATED_SUCCESSFULLY.equals(vmCrashString); if (casesFile != null && crash) { test = createDummyTestForBatchTest(test); } if (watchdog != null && watchdog.killedProcess()) { result.timedOut = true; logTimeout(feArray, test, vmCrashString); } else if (crash) { result.crashed = true; logVmCrash(feArray, test, vmCrashString); } if (!FILE_UTILS.tryHardToDelete(propsFile)) { String msg = "Could not delete temporary properties file '" + propsFile.getAbsolutePath() + "'."; if (success) { throw new BuildException(msg); //NOSONAR } // don't hide inner exception log(msg, Project.MSG_ERR); } } return result; } /** * Adding ant runtime. * @param cmd command to run */ private void checkIncludeAntRuntime(final CommandlineJava cmd) { if (includeAntRuntime) { final Map<String, String> env = Execute.getEnvironmentVariables(); final String cp = env.get(CLASSPATH); if (cp != null) { cmd.createClasspath(getProject()).createPath() .append(new Path(getProject(), cp)); } log("Implicitly adding " + antRuntimeClasses + " to CLASSPATH", Project.MSG_VERBOSE); cmd.createClasspath(getProject()).createPath() .append(antRuntimeClasses); } } /** * check for the parameter being "withoutanderr" in a locale-independent way. * @param summaryOption the summary option -can be null * @return true if the run should be withoutput and error */ private boolean equalsWithOutAndErr(final String summaryOption) { return "withoutanderr".equalsIgnoreCase(summaryOption); } private void checkIncludeSummary(final CommandlineJava cmd) { if (summary) { String prefix = ""; if (equalsWithOutAndErr(summaryValue)) { prefix = "OutErr"; } cmd.createArgument() .setValue(Constants.FORMATTER + "org.apache.tools.ant.taskdefs.optional.junit." + prefix + "SummaryJUnitResultFormatter"); } } /** * Check the path for multiple different versions of * ant. * @param cmd command to execute */ private void checkForkedPath(final CommandlineJava cmd) { if (forkedPathChecked) { return; } forkedPathChecked = true; if (!cmd.haveClasspath()) { return; } try (AntClassLoader loader = AntClassLoader.newAntClassLoader(null, getProject(), cmd.createClasspath(getProject()), false)) { loader.setIsolated(true); final String projectResourceName = LoaderUtils.classNameToResource(Project.class.getName()); URL previous = null; try { for (final URL current : Collections.list(loader.getResources(projectResourceName))) { if (previous != null && !urlEquals(current, previous)) { log(String.format( "WARNING: multiple versions of ant detected in path for junit%n" + " %s%n and %s", previous, current), Project.MSG_WARN); return; } previous = current; } } catch (final Exception ex) { // Ignore exception } } } /** * Compares URLs for equality but takes case-sensitivity into * account when comparing file URLs and ignores the jar specific * part of the URL if present. */ private static boolean urlEquals(final URL u1, final URL u2) { final String url1 = maybeStripJarAndClass(u1); final String url2 = maybeStripJarAndClass(u2); if (url1.startsWith("file:") && url2.startsWith("file:")) { return new File(FILE_UTILS.fromURI(url1)) .equals(new File(FILE_UTILS.fromURI(url2))); } return url1.equals(url2); } private static String maybeStripJarAndClass(final URL u) { String s = u.toString(); if (s.startsWith("jar:")) { final int pling = s.indexOf('!'); s = s.substring(4, pling == -1 ? s.length() : pling); } return s; } /** * Create a temporary file to pass the properties to a new process. * Will auto-delete on (graceful) exit. * The file will be in the project basedir unless tmpDir declares * something else. * @param prefix String * @return created file */ private File createTempPropertiesFile(final String prefix) { return FILE_UTILS.createTempFile(getProject(), prefix, ".properties", tmpDir != null ? tmpDir : getProject().getBaseDir(), true, true); } /** * Pass output sent to System.out to the TestRunner so it can * collect it for the formatters. * * @param output output coming from System.out * @since Ant 1.5 */ @Override protected void handleOutput(final String output) { if (output.startsWith(TESTLISTENER_PREFIX)) { log(output, Project.MSG_VERBOSE); } else if (runner != null) { if (outputToFormatters) { runner.handleOutput(output); } if (showOutput) { super.handleOutput(output); } } else { super.handleOutput(output); } } /** * Handle an input request by this task. * @see Task#handleInput(byte[], int, int) * This implementation delegates to a runner if it * present. * @param buffer the buffer into which data is to be read. * @param offset the offset into the buffer at which data is stored. * @param length the amount of data to read. * * @return the number of bytes read. * @exception IOException if the data cannot be read. * * @since Ant 1.6 */ @Override protected int handleInput(final byte[] buffer, final int offset, final int length) throws IOException { if (runner != null) { return runner.handleInput(buffer, offset, length); } return super.handleInput(buffer, offset, length); } /** * Pass output sent to System.out to the TestRunner so it can * collect ot for the formatters. * * @param output output coming from System.out * @since Ant 1.5.2 */ @Override protected void handleFlush(final String output) { if (runner != null) { runner.handleFlush(output); if (showOutput) { super.handleFlush(output); } } else { super.handleFlush(output); } } /** * Pass output sent to System.err to the TestRunner so it can * collect it for the formatters. * * @param output output coming from System.err * @since Ant 1.5 */ @Override public void handleErrorOutput(final String output) { if (runner != null) { runner.handleErrorOutput(output); if (showOutput) { super.handleErrorOutput(output); } } else { super.handleErrorOutput(output); } } /** * Pass output sent to System.err to the TestRunner so it can * collect it for the formatters. * * @param output coming from System.err * @since Ant 1.5.2 */ @Override public void handleErrorFlush(final String output) { if (runner != null) { runner.handleErrorFlush(output); if (showOutput) { super.handleErrorFlush(output); } } else { super.handleErrorFlush(output); } } // in VM is not very nice since it could probably hang the // whole build. IMHO this method should be avoided and it would be best // to remove it in future versions. TBD. (SBa) /** * Execute inside VM. * @param arg one JUnitTest * @throws BuildException under unspecified circumstances * @return the results */ private TestResultHolder executeInVM(final JUnitTest arg) throws BuildException { if (delegate == null) { setupJUnitDelegate(); } final JUnitTest test = (JUnitTest) arg.clone(); test.setProperties(getProject().getProperties()); if (dir != null) { log("dir attribute ignored if running in the same VM", Project.MSG_WARN); } if (newEnvironment || null != env.getVariables()) { log("Changes to environment variables are ignored if running in " + "the same VM.", Project.MSG_WARN); } if (getCommandline().getBootclasspath() != null) { log("bootclasspath is ignored if running in the same VM.", Project.MSG_WARN); } final CommandlineJava.SysProperties sysProperties = getCommandline().getSystemProperties(); if (sysProperties != null) { sysProperties.setSystem(); } try { log("Using System properties " + System.getProperties(), Project.MSG_VERBOSE); if (splitJUnit) { classLoader = (AntClassLoader) delegate.getClass().getClassLoader(); } else { createClassLoader(); } if (classLoader != null) { classLoader.setThreadContextLoader(); } runner = delegate.newJUnitTestRunner(test, test.getMethods(), test.getHaltonerror(), test.getFiltertrace(), test.getHaltonfailure(), false, getEnableTestListenerEvents(), classLoader); if (summary) { final JUnitTaskMirror.SummaryJUnitResultFormatterMirror f = delegate.newSummaryJUnitResultFormatter(); f.setWithOutAndErr(equalsWithOutAndErr(summaryValue)); f.setOutput(getDefaultOutput()); runner.addFormatter(f); } runner.setPermissions(perm); for (final FormatterElement fe : mergeFormatters(test)) { if (fe.shouldUse(this)) { final File outFile = getOutput(fe, test); if (outFile != null) { fe.setOutfile(outFile); } else { fe.setOutput(getDefaultOutput()); } runner.addFormatter(fe.createFormatter(classLoader)); } } runner.run(); final TestResultHolder result = new TestResultHolder(); result.exitCode = runner.getRetCode(); return result; } finally { if (sysProperties != null) { sysProperties.restoreSystem(); } if (classLoader != null) { classLoader.resetThreadContextLoader(); } } } /** * @return <code>null</code> if there is a timeout value, otherwise the * watchdog instance. * * @throws BuildException under unspecified circumstances * @since Ant 1.2 */ protected ExecuteWatchdog createWatchdog() throws BuildException { if (timeout == null) { return null; } return new ExecuteWatchdog((long) timeout); } /** * Get the default output for a formatter. * * @return default output stream for a formatter * @since Ant 1.3 */ protected OutputStream getDefaultOutput() { return new LogOutputStream(this, Project.MSG_INFO); } /** * Merge all individual tests from the batchtest with all individual tests * and return an enumeration over all <code>JUnitTest</code>. * * @return enumeration over individual tests * @since Ant 1.3 */ protected Enumeration<JUnitTest> getIndividualTests() { return Collections.enumeration(Stream.concat(batchTests.stream() .flatMap(b -> Collections.list(b.elements()).stream()), tests.stream()) .collect(Collectors.toList())); } /** * 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; } tests.stream().filter(test -> test.hasMethodsSpecified() && test.shouldRun(getProject())) .forEach(JUnitTest::resolveMethods); } /** * Checks a validity of module specific options. * @since 1.9.8 */ private void checkModules() { if (hasPath(getCommandline().getModulepath()) || hasPath(getCommandline().getUpgrademodulepath())) { if (!batchTests.stream().allMatch(BaseTest::getFork) || !tests.stream().allMatch(BaseTest::getFork)) { throw new BuildException( "The module path requires fork attribute to be set to true."); } } } /** * Checks is a junit is on given path. * @param path the {@link Path} to check * @return true when given {@link Path} contains junit * @since 1.9.8 */ private boolean hasJunit(final Path path) { try (AntClassLoader loader = AntClassLoader.newAntClassLoader( null, getProject(), path, true)) { try { loader.loadClass("junit.framework.Test"); return true; } catch (final Exception ex) { return false; } } } /** * Expands a module path to flat path of jars and root folders usable by classloader. * @param modulePath to be expanded * @return the expanded path * @since 1.9.8 */ private Path expandModulePath(Path modulePath) { final Path expanded = new Path(getProject()); for (String path : modulePath.list()) { final File modulePathEntry = getProject().resolveFile(path); if (modulePathEntry.isDirectory() && !hasModuleInfo(modulePathEntry)) { final File[] modules = modulePathEntry.listFiles((dir, name) -> name.toLowerCase(Locale.ENGLISH).endsWith(".jar")); if (modules != null) { for (File module : modules) { expanded.add(new Path(getProject(), String.format( "%s%s%s", //NOI18N path, File.separator, module.getName()))); } } } else { expanded.add(new Path(getProject(), path)); } } return expanded; } /** * return an enumeration listing each test, then each batchtest * @return enumeration * @since Ant 1.3 */ protected Enumeration<BaseTest> allTests() { return Collections.enumeration(Stream.concat(tests.stream(), batchTests.stream()) .collect(Collectors.toList())); } /** * @param test junit test * @return array of FormatterElement * @since Ant 1.3 */ private FormatterElement[] mergeFormatters(final JUnitTest test) { @SuppressWarnings("unchecked") final Vector<FormatterElement> feVector = (Vector<FormatterElement>) formatters.clone(); test.addFormattersTo(feVector); final FormatterElement[] feArray = new FormatterElement[feVector.size()]; feVector.copyInto(feArray); return feArray; } /** * If the formatter sends output to a file, return that file. * null otherwise. * @param fe formatter element * @param test one JUnit test * @return file reference * @since Ant 1.3 */ protected File getOutput(final FormatterElement fe, final JUnitTest test) { if (fe.getUseFile()) { String base = test.getOutfile(); if (base == null) { base = JUnitTaskMirror.JUnitTestRunnerMirror.IGNORED_FILE_NAME; } final String filename = base + fe.getExtension(); final File destFile = new File(test.getTodir(), filename); final String absFilename = destFile.getAbsolutePath(); return getProject().resolveFile(absFilename); } return null; } /** * Search for the given resource and add the directory or archive * that contains it to the classpath. * * <p>Doesn't work for archives in JDK 1.1 as the URL returned by * getResource doesn't contain the name of the archive.</p> * * @param resource resource that one wants to lookup * @since Ant 1.4 */ protected void addClasspathEntry(final String resource) { addClasspathResource(resource); } /** * Implementation of addClasspathEntry. * * @param resource resource that one wants to lookup * @return true if something was in fact added * @since Ant 1.7.1 */ private boolean addClasspathResource(String resource) { /* * pre Ant 1.6 this method used to call getClass().getResource * while Ant 1.6 will call ClassLoader.getResource(). * * The difference is that Class.getResource expects a leading * slash for "absolute" resources and will strip it before * delegating to ClassLoader.getResource - so we now have to * emulate Class's behavior. */ if (resource.startsWith("/")) { resource = resource.substring(1); } else { resource = "org/apache/tools/ant/taskdefs/optional/junit/" + resource; } final File f = LoaderUtils.getResourceSource(JUnitTask.class.getClassLoader(), resource); if (f != null) { log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG); antRuntimeClasses.createPath().setLocation(f); return true; } else { log("Couldn't find " + resource, Project.MSG_DEBUG); return false; } } static final String TIMEOUT_MESSAGE = "Timeout occurred. Please note the time in the report does" + " not reflect the time until the timeout."; /** * Take care that some output is produced in report files if the * watchdog kills the test. * * @since Ant 1.5.2 */ private void logTimeout(final FormatterElement[] feArray, final JUnitTest test, final String testCase) { logVmExit(feArray, test, TIMEOUT_MESSAGE, testCase); } /** * Take care that some output is produced in report files if the * forked machine exited before the test suite finished but the * reason is not a timeout. * * @since Ant 1.7 */ private void logVmCrash(final FormatterElement[] feArray, final JUnitTest test, final String testCase) { logVmExit( feArray, test, "Forked Java VM exited abnormally. Please note the time in the report" + " does not reflect the time until the VM exit.", testCase); } /** * Take care that some output is produced in report files if the * forked machine terminated before the test suite finished * * @since Ant 1.7 */ private void logVmExit(final FormatterElement[] feArray, final JUnitTest test, final String message, final String testCase) { if (delegate == null) { setupJUnitDelegate(); } try { log("Using System properties " + System.getProperties(), Project.MSG_VERBOSE); if (splitJUnit) { classLoader = (AntClassLoader) delegate.getClass().getClassLoader(); } else { createClassLoader(); } if (classLoader != null) { classLoader.setThreadContextLoader(); } test.setCounts(1, 0, 1, 0); test.setProperties(getProject().getProperties()); for (final FormatterElement fe : feArray) { if (fe.shouldUse(this)) { final JUnitTaskMirror.JUnitResultFormatterMirror formatter = fe.createFormatter(classLoader); if (formatter != null) { OutputStream out = null; final File outFile = getOutput(fe, test); if (outFile != null) { try { out = Files.newOutputStream(outFile.toPath()); } catch (final IOException e) { // ignore } } if (out == null) { out = getDefaultOutput(); } delegate.addVmExit(test, formatter, out, message, testCase); } } } if (summary) { final JUnitTaskMirror.SummaryJUnitResultFormatterMirror f = delegate.newSummaryJUnitResultFormatter(); f.setWithOutAndErr(equalsWithOutAndErr(summaryValue)); delegate.addVmExit(test, f, getDefaultOutput(), message, testCase); } } finally { if (classLoader != null) { classLoader.resetThreadContextLoader(); } } } /** * Creates and configures an AntClassLoader instance from the * nested classpath element. * * @since Ant 1.6 */ private void createClassLoader() { final Path userClasspath = getCommandline().getClasspath(); final Path userModulepath = getCommandline().getModulepath(); if (userClasspath != null || userModulepath != null) { if (reloading || classLoader == null) { deleteClassLoader(); final Path path = new Path(getProject()); if (userClasspath != null) { path.add((Path) userClasspath.clone()); } if (userModulepath != null && !hasJunit(path)) { path.add(expandModulePath(userModulepath)); } if (includeAntRuntime) { log("Implicitly adding " + antRuntimeClasses + " to CLASSPATH", Project.MSG_VERBOSE); path.append(antRuntimeClasses); } classLoader = getProject().createClassLoader(path); if (getClass().getClassLoader() != null && getClass().getClassLoader() != Project.class.getClassLoader()) { classLoader.setParent(getClass().getClassLoader()); } classLoader.setParentFirst(false); classLoader.addJavaLibraries(); log("Using CLASSPATH " + classLoader.getClasspath(), Project.MSG_VERBOSE); // make sure the test will be accepted as a TestCase classLoader.addSystemPackageRoot("junit"); // make sure the test annotation are accepted classLoader.addSystemPackageRoot("org.junit"); // will cause trouble in JDK 1.1 if omitted classLoader.addSystemPackageRoot(MagicNames.ANT_CORE_PACKAGE); } } } /** * Removes resources. * * <p>Is invoked in {@link #execute execute}. Subclasses that * don't invoke execute should invoke this method in a finally * block.</p> * * @since Ant 1.7.1 */ protected void cleanup() { deleteClassLoader(); delegate = null; } /** * Removes a classloader if needed. * @since Ant 1.7 */ private void deleteClassLoader() { if (classLoader != null) { classLoader.cleanup(); classLoader = null; } if (mirrorLoader instanceof SplitClassLoader) { ((SplitClassLoader) mirrorLoader).cleanup(); } mirrorLoader = null; } /** * Get the command line used to run the tests. * @return the command line. * @since Ant 1.6.2 */ protected CommandlineJava getCommandline() { if (commandline == null) { commandline = new CommandlineJava(); commandline.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner"); } return commandline; } /** * Forked test support * @since Ant 1.6.2 */ private static final class ForkedTestConfiguration { private final boolean filterTrace; private final boolean haltOnError; private final boolean haltOnFailure; private final String errorProperty; private final String failureProperty; /** * constructor for forked test configuration * @param filterTrace boolean * @param haltOnError boolean * @param haltOnFailure boolean * @param errorProperty String * @param failureProperty String */ ForkedTestConfiguration(final boolean filterTrace, final boolean haltOnError, final boolean haltOnFailure, final String errorProperty, final String failureProperty) { this.filterTrace = filterTrace; this.haltOnError = haltOnError; this.haltOnFailure = haltOnFailure; this.errorProperty = errorProperty; this.failureProperty = failureProperty; } /** * configure from a test; sets member variables to attributes of the test * @param test JUnitTest */ ForkedTestConfiguration(final JUnitTest test) { this(test.getFiltertrace(), test.getHaltonerror(), test.getHaltonfailure(), test.getErrorProperty(), test.getFailureProperty()); } /** * equality test checks all the member variables * @param other object to compare * @return true if everything is equal */ @Override public boolean equals(final Object other) { if (other == null || other.getClass() != ForkedTestConfiguration.class) { return false; } final ForkedTestConfiguration o = (ForkedTestConfiguration) other; return filterTrace == o.filterTrace && haltOnError == o.haltOnError && haltOnFailure == o.haltOnFailure && ((errorProperty == null && o.errorProperty == null) || (errorProperty != null && errorProperty.equals(o.errorProperty))) && ((failureProperty == null && o.failureProperty == null) || (failureProperty != null && failureProperty.equals(o.failureProperty))); } /** * hashcode is based only on the boolean members, and returns a value * in the range 0-7. * @return hash code value */ @Override public int hashCode() { // CheckStyle:MagicNumber OFF return (filterTrace ? 1 : 0) + (haltOnError ? 2 : 0) + (haltOnFailure ? 4 : 0); // CheckStyle:MagicNumber ON } } /** * These are the different forking options * @since 1.6.2 */ public static final class ForkMode extends EnumeratedAttribute { /** * fork once only */ public static final String ONCE = "once"; /** * fork once per test class */ public static final String PER_TEST = "perTest"; /** * fork once per batch of tests */ public static final String PER_BATCH = "perBatch"; /** No arg constructor. */ public ForkMode() { super(); } /** * Constructor using a value. * @param value the value to use - once, perTest or perBatch. */ public ForkMode(final String value) { super(); setValue(value); } /** {@inheritDoc}. */ @Override public String[] getValues() { return new String[] {ONCE, PER_TEST, PER_BATCH}; } } /** * Executes all tests that don't need to be forked (or all tests * if the runIndividual argument is true. Returns a collection of * lists of tests that share the same VM configuration and haven't * been executed yet. * @param testList the list of tests to be executed or queued. * @param runIndividual if true execute each test individually. * @return a list of tasks to be executed. * @since 1.6.2 */ protected Collection<List<JUnitTest>> executeOrQueue( final Enumeration<JUnitTest> testList, final boolean runIndividual) { final Map<ForkedTestConfiguration, List<JUnitTest>> testConfigurations = new HashMap<>(); for (final JUnitTest test : Collections.list(testList)) { if (test.shouldRun(getProject())) { /* with multi-threaded runs need to defer execution of even */ /* individual tests so the threads can pick tests off the queue. */ if ((runIndividual || !test.getFork()) && threads == 1) { execute(test, 0); } else { testConfigurations .computeIfAbsent(new ForkedTestConfiguration(test), k -> new ArrayList<>()) .add(test); } } } return testConfigurations.values(); } /** * Logs information about failed tests, potentially stops * processing (by throwing a BuildException) if a failure/error * occurred or sets a property. * @param exitValue the exitValue of the test. * @param wasKilled if true, the test had been killed. * @param test the test in question. * @param name the name of the test. * @since Ant 1.6.2 */ protected void actOnTestResult(final int exitValue, final boolean wasKilled, final JUnitTest test, final String name) { final TestResultHolder t = new TestResultHolder(); t.exitCode = exitValue; t.timedOut = wasKilled; actOnTestResult(t, test, name); } /** * Logs information about failed tests, potentially stops * processing (by throwing a BuildException) if a failure/error * occurred or sets a property. * @param result the result of the test. * @param test the test in question. * @param name the name of the test. * @since Ant 1.7 */ protected void actOnTestResult(final TestResultHolder result, final JUnitTest test, final String name) { // if there is an error/failure and that it should halt, stop // everything otherwise just log a statement final boolean fatal = result.timedOut || result.crashed; final boolean errorOccurredHere = result.exitCode == JUnitTaskMirror.JUnitTestRunnerMirror.ERRORS || fatal; final boolean failureOccurredHere = result.exitCode != JUnitTaskMirror.JUnitTestRunnerMirror.SUCCESS || fatal; if (errorOccurredHere || failureOccurredHere) { if ((errorOccurredHere && test.getHaltonerror()) || (failureOccurredHere && test.getHaltonfailure())) { throw new BuildException(name + " failed" + (result.timedOut ? " (timeout)" : "") + (result.crashed ? " (crashed)" : ""), getLocation()); } else { if (logFailedTests) { log(name + " FAILED" + (result.timedOut ? " (timeout)" : "") + (result.crashed ? " (crashed)" : ""), Project.MSG_ERR); } if (errorOccurredHere && test.getErrorProperty() != null) { getProject().setNewProperty(test.getErrorProperty(), "true"); } if (failureOccurredHere && test.getFailureProperty() != null) { getProject().setNewProperty(test.getFailureProperty(), "true"); } } } } /** * A value class that contains the result of a test. */ protected static class TestResultHolder { // CheckStyle:VisibilityModifier OFF - bc /** the exit code of the test. */ public int exitCode = JUnitTaskMirror.JUnitTestRunnerMirror.ERRORS; /** true if the test timed out */ public boolean timedOut = false; /** true if the test crashed */ public boolean crashed = false; // CheckStyle:VisibilityModifier ON } /** * A stream handler for handling the junit task. * @since Ant 1.7 */ protected static class JUnitLogOutputStream extends LogOutputStream { private final Task task; // local copy since LogOutputStream.task is private /** * Constructor. * @param task the task being logged. * @param level the log level used to log data written to this stream. */ public JUnitLogOutputStream(final Task task, final int level) { super(task, level); this.task = task; } /** * Logs a line. * If the line starts with junit.framework.TestListener: set the level * to MSG_VERBOSE. * @param line the line to log. * @param level the logging level to use. */ @Override protected void processLine(final String line, final int level) { if (line.startsWith(TESTLISTENER_PREFIX)) { task.log(line, Project.MSG_VERBOSE); } else { super.processLine(line, level); } } } /** * A log stream handler for junit. * @since Ant 1.7 */ protected static class JUnitLogStreamHandler extends PumpStreamHandler { /** * Constructor. * @param task the task to log. * @param outlevel the level to use for standard output. * @param errlevel the level to use for error output. */ public JUnitLogStreamHandler(final Task task, final int outlevel, final int errlevel) { super(new JUnitLogOutputStream(task, outlevel), new LogOutputStream(task, errlevel)); } } static final String NAME_OF_DUMMY_TEST = "Batch-With-Multiple-Tests"; /** * Creates a JUnitTest instance that shares all flags with the * passed in instance but has a more meaningful name. * * <p>If a VM running multiple tests crashes, we don't know which * test failed. Prior to Ant 1.8.0 Ant would log the error with * the last test of the batch test, which caused some confusion * since the log might look as if a test had been executed last * that was never started. With Ant 1.8.0 the test's name will * indicate that something went wrong with a test inside the batch * without giving it a real name.</p> * * @see "https://issues.apache.org/bugzilla/show_bug.cgi?id=45227" */ private static JUnitTest createDummyTestForBatchTest(final JUnitTest test) { final JUnitTest t = (JUnitTest) test.clone(); final int index = test.getName().lastIndexOf('.'); // make sure test looks as if it was in the same "package" as // the last test of the batch final String pack = index > 0 ? test.getName().substring(0, index + 1) : ""; t.setName(pack + NAME_OF_DUMMY_TEST); return t; } private static void printDual(final BufferedWriter w, final PrintStream s, final String text) throws IOException { w.write(String.valueOf(text)); s.print(text); } private static void printlnDual(final BufferedWriter w, final PrintStream s, final String text) throws IOException { w.write(String.valueOf(text)); w.newLine(); s.println(text); } /** * Checks if a path exists and is non empty. * @param path to be checked * @return true if the path is non <code>null</code> and non empty. * @since 1.9.8 */ private static boolean hasPath(final Path path) { return path != null && path.size() > 0; } /** * Checks if a given folder is an unpacked module. * @param root the folder to be checked * @return true if the root is an unpacked module * @since 1.9.8 */ private static boolean hasModuleInfo(final File root) { return new File(root, "module-info.class").exists(); //NOI18N } }
⏎ org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
Or download all of them as a single archive file:
File name: apache-ant-1.10.10-fyi.zip File size: 2392938 bytes Release date: 2021-04-17 Download
⇐ Download Apache Ant Source Package
2021-07-10, 109667👍, 0💬
Popular Posts:
JDK 11 jdk.internal.le.jmod is the JMOD file for JDK 11 Internal Line Editing module. JDK 11 Interna...
JasperReports, the world's most popular open source business intelligence and reporting engine and J...
JDK 11 jdk.rmic.jmod is the JMOD file for JDK 11 RMI (Remote Method Invocation) Compiler Tool tool, ...
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms, it was develo...
What Is poi-5.2.3.jar? poi-5.2.3.jar is one of the JAR files for Apache POI 5.2.3, which provides an...