[GitHub] ant pull request #60: JUnit 5 support - A new junitlauncher task
Github user bodewig commented on a diff in the pull request: https://github.com/apache/ant/pull/60#discussion_r172043778 --- Diff: src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/AbstractJUnitResultFormatter.java --- @@ -0,0 +1,295 @@ +package org.apache.tools.ant.taskdefs.optional.junitlauncher; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.util.FileUtils; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.Closeable; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.Writer; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; + +/** + * Contains some common behaviour that's used by our internal {@link TestResultFormatter}s + */ +abstract class AbstractJUnitResultFormatter implements TestResultFormatter { + + +protected static String NEW_LINE = System.getProperty("line.separator"); +protected Task task; + +private SysOutErrContentStore sysOutStore; +private SysOutErrContentStore sysErrStore; + +@Override +public void sysOutAvailable(final byte[] data) { +if (this.sysOutStore == null) { +this.sysOutStore = new SysOutErrContentStore(true); +} +try { +this.sysOutStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void sysErrAvailable(final byte[] data) { +if (this.sysErrStore == null) { +this.sysErrStore = new SysOutErrContentStore(false); +} +try { +this.sysErrStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void setExecutingTask(final Task task) { +this.task = task; +} + +/** + * @return Returns true if there's any stdout data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysOut() { +return this.sysOutStore != null && this.sysOutStore.hasData(); +} + +/** + * @return Returns true if there's any stderr data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysErr() { +return this.sysErrStore != null && this.sysErrStore.hasData(); +} + +/** + * @return Returns a {@link Reader} for reading any stdout data that was generated + * during the test execution. It is expected that the {@link #hasSysOut()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysOutReader() throws IOException { +return this.sysOutStore.getReader(); +} + +/** + * @return Returns a {@link Reader} for reading any stderr data that was generated + * during the test execution. It is expected that the {@link #hasSysErr()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysErrReader() throws IOException { +return this.sysErrStore.getReader(); +} + +/** + * Writes out any stdout data that was generated during the + * test execution. If there was no such data then this method just returns. + * + * @param writer The {@link Writer} to use. Cannot be null. + * @throws IOException If any I/O problem occurs during writing the data + */ +void writeSysOut(final Writer writer) throws IOException { +Objects.requireNonNull(writer, "Writer cannot be null"); +this.writeFrom(this.sysOutStore, writer); +} + +/** + * Writes out any stderr data that was generated during the + * test execution. If there was no such data then this me
[GitHub] ant pull request #60: JUnit 5 support - A new junitlauncher task
Github user bodewig commented on a diff in the pull request: https://github.com/apache/ant/pull/60#discussion_r172043835 --- Diff: src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/AbstractJUnitResultFormatter.java --- @@ -0,0 +1,295 @@ +package org.apache.tools.ant.taskdefs.optional.junitlauncher; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.util.FileUtils; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.Closeable; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.Writer; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; + +/** + * Contains some common behaviour that's used by our internal {@link TestResultFormatter}s + */ +abstract class AbstractJUnitResultFormatter implements TestResultFormatter { + + +protected static String NEW_LINE = System.getProperty("line.separator"); +protected Task task; + +private SysOutErrContentStore sysOutStore; +private SysOutErrContentStore sysErrStore; + +@Override +public void sysOutAvailable(final byte[] data) { +if (this.sysOutStore == null) { +this.sysOutStore = new SysOutErrContentStore(true); +} +try { +this.sysOutStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void sysErrAvailable(final byte[] data) { +if (this.sysErrStore == null) { +this.sysErrStore = new SysOutErrContentStore(false); +} +try { +this.sysErrStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void setExecutingTask(final Task task) { +this.task = task; +} + +/** + * @return Returns true if there's any stdout data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysOut() { +return this.sysOutStore != null && this.sysOutStore.hasData(); +} + +/** + * @return Returns true if there's any stderr data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysErr() { +return this.sysErrStore != null && this.sysErrStore.hasData(); +} + +/** + * @return Returns a {@link Reader} for reading any stdout data that was generated + * during the test execution. It is expected that the {@link #hasSysOut()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysOutReader() throws IOException { +return this.sysOutStore.getReader(); +} + +/** + * @return Returns a {@link Reader} for reading any stderr data that was generated + * during the test execution. It is expected that the {@link #hasSysErr()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysErrReader() throws IOException { +return this.sysErrStore.getReader(); +} + +/** + * Writes out any stdout data that was generated during the + * test execution. If there was no such data then this method just returns. + * + * @param writer The {@link Writer} to use. Cannot be null. + * @throws IOException If any I/O problem occurs during writing the data + */ +void writeSysOut(final Writer writer) throws IOException { +Objects.requireNonNull(writer, "Writer cannot be null"); +this.writeFrom(this.sysOutStore, writer); +} + +/** + * Writes out any stderr data that was generated during the + * test execution. If there was no such data then this me
[GitHub] ant pull request #60: JUnit 5 support - A new junitlauncher task
Github user bodewig commented on a diff in the pull request: https://github.com/apache/ant/pull/60#discussion_r172043964 --- Diff: src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTask.java --- @@ -0,0 +1,508 @@ +package org.apache.tools.ant.taskdefs.optional.junitlauncher; + +import org.apache.tools.ant.AntClassLoader; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.KeepAliveOutputStream; +import org.junit.platform.launcher.Launcher; +import org.junit.platform.launcher.LauncherDiscoveryRequest; +import org.junit.platform.launcher.TestExecutionListener; +import org.junit.platform.launcher.TestPlan; +import org.junit.platform.launcher.core.LauncherFactory; +import org.junit.platform.launcher.listeners.SummaryGeneratingListener; +import org.junit.platform.launcher.listeners.TestExecutionSummary; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * An Ant {@link Task} responsible for launching the JUnit platform for running tests. + * This requires a minimum of JUnit 5, since that's the version in which the JUnit platform launcher + * APIs were introduced. + * + * This task in itself doesn't run the JUnit tests, instead the sole responsibility of + * this task is to setup the JUnit platform launcher, build requests, launch those requests and then parse the + * result of the execution to present in a way that's been configured on this Ant task. + * + * + * Furthermore, this task allows users control over which classes to select for passing on to the JUnit 5 + * platform for test execution. It however, is solely the JUnit 5 platform, backed by test engines that + * decide and execute the tests. + * + * @see https://junit.org/junit5/";>JUnit 5 documentation for more details + * on how JUnit manages the platform and the test engines. + */ +public class JUnitLauncherTask extends Task { + +private Path classPath; +private boolean haltOnFailure; +private String failureProperty; +private final List tests = new ArrayList<>(); +private final List listeners = new ArrayList<>(); + +public JUnitLauncherTask() { +} + +@Override +public void execute() throws BuildException { +final ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader(); +try { +final ClassLoader executionCL = createClassLoaderForTestExecution(); +Thread.currentThread().setContextClassLoader(executionCL); +final Launcher launcher = LauncherFactory.create(); +final List requests = buildTestRequests(); +for (final TestRequest testRequest : requests) { +try { +final TestDefinition test = testRequest.getOwner(); +final LauncherDiscoveryRequest request = testRequest.getDiscoveryRequest().build(); +final List testExecutionListeners = new ArrayList<>(); +// a listener that we always put at the front of list of listeners +// for this request. +final Listener firstListener = new Listener(); +// we always enroll the summary generating listener, to the request, so that we +// get to use some of the details of the summary for our further decision making +testExecutionListeners.add(firstListener); + testExecutionListeners.addAll(getListeners(testRequest, executionCL)); +final PrintStream originalSysOut = System.out; +final PrintStream originalSysErr = System.err; +try { +firstListener.switchedSysOutHandle = trySwitchSysOut(testRequest); +firstListener.switchedSysErrHandle = trySwitchSysErr(testRequest); +launcher.execute(request, testExecutionListeners
[GitHub] ant issue #60: JUnit 5 support - A new junitlauncher task
Github user bodewig commented on the issue: https://github.com/apache/ant/pull/60 Nice work! I don't see any reason not to merge this PR. --- - To unsubscribe, e-mail: dev-unsubscr...@ant.apache.org For additional commands, e-mail: dev-h...@ant.apache.org
[GitHub] ant pull request #60: JUnit 5 support - A new junitlauncher task
Github user jaikiran commented on a diff in the pull request: https://github.com/apache/ant/pull/60#discussion_r172044509 --- Diff: src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/AbstractJUnitResultFormatter.java --- @@ -0,0 +1,295 @@ +package org.apache.tools.ant.taskdefs.optional.junitlauncher; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.util.FileUtils; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.Closeable; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.Writer; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; + +/** + * Contains some common behaviour that's used by our internal {@link TestResultFormatter}s + */ +abstract class AbstractJUnitResultFormatter implements TestResultFormatter { + + +protected static String NEW_LINE = System.getProperty("line.separator"); +protected Task task; + +private SysOutErrContentStore sysOutStore; +private SysOutErrContentStore sysErrStore; + +@Override +public void sysOutAvailable(final byte[] data) { +if (this.sysOutStore == null) { +this.sysOutStore = new SysOutErrContentStore(true); +} +try { +this.sysOutStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void sysErrAvailable(final byte[] data) { +if (this.sysErrStore == null) { +this.sysErrStore = new SysOutErrContentStore(false); +} +try { +this.sysErrStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void setExecutingTask(final Task task) { +this.task = task; +} + +/** + * @return Returns true if there's any stdout data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysOut() { +return this.sysOutStore != null && this.sysOutStore.hasData(); +} + +/** + * @return Returns true if there's any stderr data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysErr() { +return this.sysErrStore != null && this.sysErrStore.hasData(); +} + +/** + * @return Returns a {@link Reader} for reading any stdout data that was generated + * during the test execution. It is expected that the {@link #hasSysOut()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysOutReader() throws IOException { +return this.sysOutStore.getReader(); +} + +/** + * @return Returns a {@link Reader} for reading any stderr data that was generated + * during the test execution. It is expected that the {@link #hasSysErr()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysErrReader() throws IOException { +return this.sysErrStore.getReader(); +} + +/** + * Writes out any stdout data that was generated during the + * test execution. If there was no such data then this method just returns. + * + * @param writer The {@link Writer} to use. Cannot be null. + * @throws IOException If any I/O problem occurs during writing the data + */ +void writeSysOut(final Writer writer) throws IOException { +Objects.requireNonNull(writer, "Writer cannot be null"); +this.writeFrom(this.sysOutStore, writer); +} + +/** + * Writes out any stderr data that was generated during the + * test execution. If there was no such data then this m
[GitHub] ant pull request #60: JUnit 5 support - A new junitlauncher task
Github user jaikiran commented on a diff in the pull request: https://github.com/apache/ant/pull/60#discussion_r172044665 --- Diff: src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/AbstractJUnitResultFormatter.java --- @@ -0,0 +1,295 @@ +package org.apache.tools.ant.taskdefs.optional.junitlauncher; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.util.FileUtils; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.Closeable; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.Writer; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; + +/** + * Contains some common behaviour that's used by our internal {@link TestResultFormatter}s + */ +abstract class AbstractJUnitResultFormatter implements TestResultFormatter { + + +protected static String NEW_LINE = System.getProperty("line.separator"); +protected Task task; + +private SysOutErrContentStore sysOutStore; +private SysOutErrContentStore sysErrStore; + +@Override +public void sysOutAvailable(final byte[] data) { +if (this.sysOutStore == null) { +this.sysOutStore = new SysOutErrContentStore(true); +} +try { +this.sysOutStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void sysErrAvailable(final byte[] data) { +if (this.sysErrStore == null) { +this.sysErrStore = new SysOutErrContentStore(false); +} +try { +this.sysErrStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void setExecutingTask(final Task task) { +this.task = task; +} + +/** + * @return Returns true if there's any stdout data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysOut() { +return this.sysOutStore != null && this.sysOutStore.hasData(); +} + +/** + * @return Returns true if there's any stderr data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysErr() { +return this.sysErrStore != null && this.sysErrStore.hasData(); +} + +/** + * @return Returns a {@link Reader} for reading any stdout data that was generated + * during the test execution. It is expected that the {@link #hasSysOut()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysOutReader() throws IOException { +return this.sysOutStore.getReader(); +} + +/** + * @return Returns a {@link Reader} for reading any stderr data that was generated + * during the test execution. It is expected that the {@link #hasSysErr()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysErrReader() throws IOException { +return this.sysErrStore.getReader(); +} + +/** + * Writes out any stdout data that was generated during the + * test execution. If there was no such data then this method just returns. + * + * @param writer The {@link Writer} to use. Cannot be null. + * @throws IOException If any I/O problem occurs during writing the data + */ +void writeSysOut(final Writer writer) throws IOException { +Objects.requireNonNull(writer, "Writer cannot be null"); +this.writeFrom(this.sysOutStore, writer); +} + +/** + * Writes out any stderr data that was generated during the + * test execution. If there was no such data then this m
[GitHub] ant pull request #60: JUnit 5 support - A new junitlauncher task
Github user jaikiran commented on a diff in the pull request: https://github.com/apache/ant/pull/60#discussion_r172044717 --- Diff: src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/AbstractJUnitResultFormatter.java --- @@ -0,0 +1,295 @@ +package org.apache.tools.ant.taskdefs.optional.junitlauncher; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.util.FileUtils; +import org.junit.platform.engine.TestSource; +import org.junit.platform.engine.support.descriptor.ClassSource; +import org.junit.platform.launcher.TestIdentifier; +import org.junit.platform.launcher.TestPlan; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.Closeable; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.Writer; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; + +/** + * Contains some common behaviour that's used by our internal {@link TestResultFormatter}s + */ +abstract class AbstractJUnitResultFormatter implements TestResultFormatter { + + +protected static String NEW_LINE = System.getProperty("line.separator"); +protected Task task; + +private SysOutErrContentStore sysOutStore; +private SysOutErrContentStore sysErrStore; + +@Override +public void sysOutAvailable(final byte[] data) { +if (this.sysOutStore == null) { +this.sysOutStore = new SysOutErrContentStore(true); +} +try { +this.sysOutStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void sysErrAvailable(final byte[] data) { +if (this.sysErrStore == null) { +this.sysErrStore = new SysOutErrContentStore(false); +} +try { +this.sysErrStore.store(data); +} catch (IOException e) { +handleException(e); +return; +} +} + +@Override +public void setExecutingTask(final Task task) { +this.task = task; +} + +/** + * @return Returns true if there's any stdout data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysOut() { +return this.sysOutStore != null && this.sysOutStore.hasData(); +} + +/** + * @return Returns true if there's any stderr data, that was generated during the + * tests, is available for use. Else returns false. + */ +boolean hasSysErr() { +return this.sysErrStore != null && this.sysErrStore.hasData(); +} + +/** + * @return Returns a {@link Reader} for reading any stdout data that was generated + * during the test execution. It is expected that the {@link #hasSysOut()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysOutReader() throws IOException { +return this.sysOutStore.getReader(); +} + +/** + * @return Returns a {@link Reader} for reading any stderr data that was generated + * during the test execution. It is expected that the {@link #hasSysErr()} be first + * called to see if any such data is available and only if there is, then this method + * be called + * @throws IOException If there's any I/O problem while creating the {@link Reader} + */ +Reader getSysErrReader() throws IOException { +return this.sysErrStore.getReader(); +} + +/** + * Writes out any stdout data that was generated during the + * test execution. If there was no such data then this method just returns. + * + * @param writer The {@link Writer} to use. Cannot be null. + * @throws IOException If any I/O problem occurs during writing the data + */ +void writeSysOut(final Writer writer) throws IOException { +Objects.requireNonNull(writer, "Writer cannot be null"); +this.writeFrom(this.sysOutStore, writer); +} + +/** + * Writes out any stderr data that was generated during the + * test execution. If there was no such data then this m
[GitHub] ant issue #60: JUnit 5 support - A new junitlauncher task
Github user jaikiran commented on the issue: https://github.com/apache/ant/pull/60 Thank you Stefan for the thorough review. I'll clean up the commits to squash them into one and do these minor final changes before merging. --- - To unsubscribe, e-mail: dev-unsubscr...@ant.apache.org For additional commands, e-mail: dev-h...@ant.apache.org
[GitHub] ant pull request #60: JUnit 5 support - A new junitlauncher task
Github user jaikiran commented on a diff in the pull request: https://github.com/apache/ant/pull/60#discussion_r172044906 --- Diff: src/main/org/apache/tools/ant/taskdefs/optional/junitlauncher/JUnitLauncherTask.java --- @@ -0,0 +1,508 @@ +package org.apache.tools.ant.taskdefs.optional.junitlauncher; + +import org.apache.tools.ant.AntClassLoader; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.KeepAliveOutputStream; +import org.junit.platform.launcher.Launcher; +import org.junit.platform.launcher.LauncherDiscoveryRequest; +import org.junit.platform.launcher.TestExecutionListener; +import org.junit.platform.launcher.TestPlan; +import org.junit.platform.launcher.core.LauncherFactory; +import org.junit.platform.launcher.listeners.SummaryGeneratingListener; +import org.junit.platform.launcher.listeners.TestExecutionSummary; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * An Ant {@link Task} responsible for launching the JUnit platform for running tests. + * This requires a minimum of JUnit 5, since that's the version in which the JUnit platform launcher + * APIs were introduced. + * + * This task in itself doesn't run the JUnit tests, instead the sole responsibility of + * this task is to setup the JUnit platform launcher, build requests, launch those requests and then parse the + * result of the execution to present in a way that's been configured on this Ant task. + * + * + * Furthermore, this task allows users control over which classes to select for passing on to the JUnit 5 + * platform for test execution. It however, is solely the JUnit 5 platform, backed by test engines that + * decide and execute the tests. + * + * @see https://junit.org/junit5/";>JUnit 5 documentation for more details + * on how JUnit manages the platform and the test engines. + */ +public class JUnitLauncherTask extends Task { + +private Path classPath; +private boolean haltOnFailure; +private String failureProperty; +private final List tests = new ArrayList<>(); +private final List listeners = new ArrayList<>(); + +public JUnitLauncherTask() { +} + +@Override +public void execute() throws BuildException { +final ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader(); +try { +final ClassLoader executionCL = createClassLoaderForTestExecution(); +Thread.currentThread().setContextClassLoader(executionCL); +final Launcher launcher = LauncherFactory.create(); +final List requests = buildTestRequests(); +for (final TestRequest testRequest : requests) { +try { +final TestDefinition test = testRequest.getOwner(); +final LauncherDiscoveryRequest request = testRequest.getDiscoveryRequest().build(); +final List testExecutionListeners = new ArrayList<>(); +// a listener that we always put at the front of list of listeners +// for this request. +final Listener firstListener = new Listener(); +// we always enroll the summary generating listener, to the request, so that we +// get to use some of the details of the summary for our further decision making +testExecutionListeners.add(firstListener); + testExecutionListeners.addAll(getListeners(testRequest, executionCL)); +final PrintStream originalSysOut = System.out; +final PrintStream originalSysErr = System.err; +try { +firstListener.switchedSysOutHandle = trySwitchSysOut(testRequest); +firstListener.switchedSysErrHandle = trySwitchSysErr(testRequest); +launcher.execute(request, testExecutionListener