Revert "Bug 531057- 2nd Attempt JUnit 5 support for tests"
This reverts commit 21df6c58ad51eafc007fb99b53e71ba72d229839.
Change-Id: I5503479bc39482ee18e69da222dd98f4c54a2245
diff --git a/bundles/org.eclipse.test/META-INF/MANIFEST.MF b/bundles/org.eclipse.test/META-INF/MANIFEST.MF
index 5b9f607..d9d11e9 100644
--- a/bundles/org.eclipse.test/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.test/META-INF/MANIFEST.MF
@@ -7,16 +7,11 @@
Bundle-Vendor: %providerName
Bundle-Localization: plugin
Require-Bundle: org.apache.ant,
+ org.junit;bundle-version="4.12.0",
org.eclipse.ui,
org.eclipse.core.runtime,
org.eclipse.ui.ide.application,
- org.eclipse.equinox.app,
- org.junit.jupiter.api,
- org.junit.jupiter.engine,
- org.junit.platform.commons,
- org.junit.platform.engine,
- org.junit.platform.launcher,
- org.junit.vintage.engine
+ org.eclipse.equinox.app
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: org.eclipse.test
diff --git a/bundles/org.eclipse.test/src/org/eclipse/test/AbstractJUnitResultFormatter.java b/bundles/org.eclipse.test/src/org/eclipse/test/AbstractJUnitResultFormatter.java
deleted file mode 100644
index 5d681aa..0000000
--- a/bundles/org.eclipse.test/src/org/eclipse/test/AbstractJUnitResultFormatter.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2018 Red Hat Inc. and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Lucas Bullen (Red Hat Inc.) - initial API and implementation
- *******************************************************************************/
-package org.eclipse.test;
-
-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;
-
-import org.apache.tools.ant.Project;
-import org.apache.tools.ant.taskdefs.optional.junitlauncher.TestExecutionContext;
-import org.apache.tools.ant.taskdefs.optional.junitlauncher.TestResultFormatter;
-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;
-
-/**
- * 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 TestExecutionContext context;
-
- 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 setContext(final TestExecutionContext context) {
- this.context = context;
- }
-
- /**
- * @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 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 writeSysErr(final Writer writer) throws IOException {
- Objects.requireNonNull(writer, "Writer cannot be null");
- this.writeFrom(this.sysErrStore, writer);
- }
-
- static Optional<TestIdentifier> traverseAndFindTestClass(final TestPlan testPlan, final TestIdentifier testIdentifier) {
- if (isTestClass(testIdentifier).isPresent()) {
- return Optional.of(testIdentifier);
- }
- final Optional<TestIdentifier> parent = testPlan.getParent(testIdentifier);
- return parent.isPresent() ? traverseAndFindTestClass(testPlan, parent.get()) : Optional.empty();
- }
-
- static Optional<ClassSource> isTestClass(final TestIdentifier testIdentifier) {
- if (testIdentifier == null) {
- return Optional.empty();
- }
- final Optional<TestSource> source = testIdentifier.getSource();
- if (!source.isPresent()) {
- return Optional.empty();
- }
- final TestSource testSource = source.get();
- if (testSource instanceof ClassSource) {
- return Optional.of((ClassSource) testSource);
- }
- return Optional.empty();
- }
-
- private void writeFrom(final SysOutErrContentStore store, final Writer writer) throws IOException {
- final char[] chars = new char[1024];
- int numRead = -1;
- try (final Reader reader = store.getReader()) {
- while ((numRead = reader.read(chars)) != -1) {
- writer.write(chars, 0, numRead);
- }
- }
- }
-
- @Override
- public void close() throws IOException {
- FileUtils.close(this.sysOutStore);
- FileUtils.close(this.sysErrStore);
- }
-
- protected void handleException(final Throwable t) {
- // we currently just log it and move on.
- this.context.getProject().ifPresent((p) -> p.log("Exception in listener "
- + AbstractJUnitResultFormatter.this.getClass().getName(), t, Project.MSG_DEBUG));
- }
-
-
- /*
- A "store" for sysout/syserr content that gets sent to the AbstractJUnitResultFormatter.
- This store first uses a relatively decent sized in-memory buffer for storing the sysout/syserr
- content. This in-memory buffer will be used as long as it can fit in the new content that
- keeps coming in. When the size limit is reached, this store switches to a file based store
- by creating a temporarily file and writing out the already in-memory held buffer content
- and any new content that keeps arriving to this store. Once the file has been created,
- the in-memory buffer will never be used any more and in fact is destroyed as soon as the
- file is created.
- Instances of this class are not thread-safe and users of this class are expected to use necessary thread
- safety guarantees, if they want to use an instance of this class by multiple threads.
- */
- private static final class SysOutErrContentStore implements Closeable {
- private static final int DEFAULT_CAPACITY_IN_BYTES = 50 * 1024; // 50 KB
- private static final Reader EMPTY_READER = new Reader() {
- @Override
- public int read(final char[] cbuf, final int off, final int len) throws IOException {
- return -1;
- }
-
- @Override
- public void close() throws IOException {
- }
- };
-
- private final String tmpFileSuffix;
- private ByteBuffer inMemoryStore = ByteBuffer.allocate(DEFAULT_CAPACITY_IN_BYTES);
- private boolean usingFileStore = false;
- private Path filePath;
- private FileOutputStream fileOutputStream;
-
- SysOutErrContentStore(final boolean isSysOut) {
- this.tmpFileSuffix = isSysOut ? ".sysout" : ".syserr";
- }
-
- void store(final byte[] data) throws IOException {
- if (this.usingFileStore) {
- this.storeToFile(data, 0, data.length);
- return;
- }
- // we haven't yet created a file store and the data can fit in memory,
- // so we write it in our buffer
- try {
- this.inMemoryStore.put(data);
- return;
- } catch (BufferOverflowException boe) {
- // the buffer capacity can't hold this incoming data, so this
- // incoming data hasn't been transferred to the buffer. let's
- // now fall back to a file store
- this.usingFileStore = true;
- }
- // since the content couldn't be transferred into in-memory buffer,
- // we now create a file and transfer already (previously) stored in-memory
- // content into that file, before finally transferring this new content
- // into the file too. We then finally discard this in-memory buffer and
- // just keep using the file store instead
- this.fileOutputStream = createFileStore();
- // first the existing in-memory content
- storeToFile(this.inMemoryStore.array(), 0, this.inMemoryStore.position());
- storeToFile(data, 0, data.length);
- // discard the in-memory store
- this.inMemoryStore = null;
- }
-
- private void storeToFile(final byte[] data, final int offset, final int length) throws IOException {
- if (this.fileOutputStream == null) {
- // no backing file was created so we can't do anything
- return;
- }
- this.fileOutputStream.write(data, offset, length);
- }
-
- private FileOutputStream createFileStore() throws IOException {
- this.filePath = Files.createTempFile(null, this.tmpFileSuffix);
- this.filePath.toFile().deleteOnExit();
- return new FileOutputStream(this.filePath.toFile());
- }
-
- /*
- * Returns a Reader for reading the sysout/syserr content. If there's no data
- * available in this store, then this returns a Reader which when used for read operations,
- * will immediately indicate an EOF.
- */
- Reader getReader() throws IOException {
- if (this.usingFileStore && this.filePath != null) {
- // we use a FileReader here so that we can use the system default character
- // encoding for reading the contents on sysout/syserr stream, since that's the
- // encoding that System.out/System.err uses to write out the messages
- return new BufferedReader(new FileReader(this.filePath.toFile()));
- }
- if (this.inMemoryStore != null) {
- return new InputStreamReader(new ByteArrayInputStream(this.inMemoryStore.array(), 0, this.inMemoryStore.position()));
- }
- // no data to read, so we return an "empty" reader
- return EMPTY_READER;
- }
-
- /*
- * Returns true if this store has any data (either in-memory or in a file). Else
- * returns false.
- */
- boolean hasData() {
- if (this.inMemoryStore != null && this.inMemoryStore.position() > 0) {
- return true;
- }
- if (this.usingFileStore && this.filePath != null) {
- return true;
- }
- return false;
- }
-
- @Override
- public void close() throws IOException {
- this.inMemoryStore = null;
- FileUtils.close(this.fileOutputStream);
- FileUtils.delete(this.filePath.toFile());
- }
- }
-}
diff --git a/bundles/org.eclipse.test/src/org/eclipse/test/ClassLoaderTools.java b/bundles/org.eclipse.test/src/org/eclipse/test/ClassLoaderTools.java
deleted file mode 100644
index 28fe538..0000000
--- a/bundles/org.eclipse.test/src/org/eclipse/test/ClassLoaderTools.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2018 Red Hat Inc. and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Lucas Bullen (Red Hat Inc.) - initial API and implementation
- *******************************************************************************/
-package org.eclipse.test;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Vector;
-
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.osgi.internal.framework.EquinoxBundle;
-import org.osgi.framework.Bundle;
-
-@SuppressWarnings("restriction")
-class ClassLoaderTools {
- public static ClassLoader getPluginClassLoader(String getfTestPluginName, ClassLoader currentTCCL) {
- Bundle bundle = Platform.getBundle(getfTestPluginName);
- if (bundle == null) {
- throw new IllegalArgumentException("Bundle \"" + getfTestPluginName + "\" not found. Possible causes include missing dependencies, too restrictive version ranges, or a non-matching required execution environment."); //$NON-NLS-1$ //$NON-NLS-2$
- }
- return new TestBundleClassLoader(bundle, currentTCCL);
- }
-
- public static String getClassPlugin(String className) {
- int index = className.lastIndexOf('.');
- String plugin = null;
- while (index != -1) {
- plugin = className.substring(0, index);
- if(Platform.getBundle(plugin) != null) {
- break;
- }
- index = className.lastIndexOf('.', index-1);
- }
- return plugin;
- }
-
- public static ClassLoader getJUnit5Classloader(List<String> platformEngine) {
- List<Bundle> platformEngineBundles = new ArrayList<>();
- for (Iterator<String> iterator = platformEngine.iterator(); iterator.hasNext();) {
- String string = iterator.next();
- Bundle bundle = Platform.getBundle(string);
- platformEngineBundles.add(bundle);
- }
- return new MultiBundleClassLoader(platformEngineBundles);
- }
-
- static class TestBundleClassLoader extends ClassLoader {
- protected Bundle bundle;
- protected ClassLoader currentTCCL;
-
- public TestBundleClassLoader(Bundle target, ClassLoader currentTCCL) {
- this.bundle = target;
- this.currentTCCL = currentTCCL;
- }
-
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- try {
- return bundle.loadClass(name);
- } catch (ClassNotFoundException e) {
- return currentTCCL.loadClass(name);
- }
- }
-
- @Override
- protected URL findResource(String name) {
- URL url = bundle.getResource(name);
- if(url == null) {
- url = currentTCCL.getResource(name);
- }
- return url;
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- @Override
- protected Enumeration findResources(String name) throws IOException {
- Enumeration enumeration = bundle.getResources(name);
- if(enumeration == null) {
- enumeration = currentTCCL.getResources(name);
- }
- return enumeration;
- }
-
- @Override
- public Enumeration<URL> getResources(String res) throws IOException {
- Enumeration<URL> urls = currentTCCL.getResources(res);
- if(urls.hasMoreElements())
- return urls;
-
- List<URL> resources = new ArrayList<>(6);
- String location = null;
- URL url = null;
- if (bundle instanceof EquinoxBundle) {
- location = ((EquinoxBundle) bundle).getLocation();
- }
- if (location != null && location.startsWith("reference:")) { //$NON-NLS-1$
- location = location.substring(10, location.length());
- URI uri = URI.create(location);
- String newPath =( uri.getPath() == null ? "" : uri.getPath()) + "bin" + '/' + res; //$NON-NLS-1$
- URI newUri = uri.resolve(newPath).normalize();
- if(newUri.isAbsolute())
- url = newUri.toURL();
- }
- if (url != null) {
- File f = new File(url.getFile());
- if (f.exists())
- resources.add(url);
- }
- else
- return Collections.emptyEnumeration();
-
- return Collections.enumeration(resources);
- }
- }
-
- static class MultiBundleClassLoader extends ClassLoader {
- private List<Bundle> bundleList;
-
- public MultiBundleClassLoader(List<Bundle> platformEngineBundles) {
- this.bundleList = platformEngineBundles;
-
- }
- public Class<?> findClasss(String name) throws ClassNotFoundException {
- return findClass(name);
- }
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- Class<?> c = null;
- for (Bundle temp : bundleList) {
- try {
- c = temp.loadClass(name);
- if (c != null)
- return c;
- } catch (ClassNotFoundException e) {
- }
- }
- return c;
- }
-
- @Override
- protected URL findResource(String name) {
- URL url = null;
- for (Bundle temp : bundleList) {
- url = temp.getResource(name);
- if (url != null)
- return url;
- }
- return url;
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- @Override
- protected Enumeration findResources(String name) throws IOException {
- Enumeration enumFinal = null;
- for (int i = 0; i < bundleList.size(); i++) {
- if (i == 0) {
- enumFinal = bundleList.get(i).getResources(name);
- continue;
- }
- Enumeration e2 = bundleList.get(i).getResources(name);
- Vector temp = new Vector();
- while (enumFinal != null && enumFinal.hasMoreElements()) {
- temp.add(enumFinal.nextElement());
- }
- while (e2 != null && e2.hasMoreElements()) {
- temp.add(e2.nextElement());
- }
- enumFinal = temp.elements();
- }
- return enumFinal;
- }
- }
-}
diff --git a/bundles/org.eclipse.test/src/org/eclipse/test/EclipseTestRunner.java b/bundles/org.eclipse.test/src/org/eclipse/test/EclipseTestRunner.java
index a653ebe..1a6b77d 100644
--- a/bundles/org.eclipse.test/src/org/eclipse/test/EclipseTestRunner.java
+++ b/bundles/org.eclipse.test/src/org/eclipse/test/EclipseTestRunner.java
@@ -8,12 +8,9 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Anthony Dahanne <anthony.dahanne@compuware.com> - enhance ETF to be able to launch several tests in several bundles - https://bugs.eclipse.org/330613
- * Lucas Bullen (Red Hat Inc.) - JUnit 5 support
*******************************************************************************/
package org.eclipse.test;
-import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
-
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -24,31 +21,33 @@
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Date;
+import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
-import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Optional;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
-import org.apache.tools.ant.taskdefs.optional.junitlauncher.TestExecutionContext;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.GC;
@@ -58,16 +57,14 @@
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
-import org.junit.platform.engine.TestExecutionResult;
-import org.junit.platform.launcher.Launcher;
-import org.junit.platform.launcher.LauncherDiscoveryRequest;
-import org.junit.platform.launcher.TestExecutionListener;
-import org.junit.platform.launcher.TestIdentifier;
-import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
-import org.junit.platform.launcher.core.LauncherFactory;
import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
/**
* A TestRunner for JUnit that supports Ant JUnitResultFormatters and running
@@ -76,7 +73,20 @@
* formatter=org.apache.tools.ant.taskdefs.optional.junit
* .XMLJUnitResultFormatter
*/
-public class EclipseTestRunner {
+public class EclipseTestRunner implements TestListener {
+ class TestFailedException extends Exception {
+
+ private static final long serialVersionUID = 6009335074727417445L;
+
+ TestFailedException(String message) {
+ super(message);
+ }
+
+ TestFailedException(Throwable e) {
+ super(e);
+ }
+ }
+
static class ThreadDump extends Exception {
private static final long serialVersionUID = 1L;
@@ -122,6 +132,7 @@
*/
public static final int ERRORS = 2;
+ private static final String SUITE_METHODNAME = "suite";
/**
* SECONDS_BEFORE_TIMEOUT_BUFFER is the time we allow ourselves to take stack
* traces, get a screen shot, delay "SECONDS_BETWEEN_DUMPS", then do it again.
@@ -139,20 +150,68 @@
private static final int SECONDS_BETWEEN_DUMPS = 5;
/**
+ * The current test result
+ */
+ private TestResult fTestResult;
+ /**
+ * The name of the plugin containing the test
+ */
+ private String fTestPluginName;
+ /**
+ * The corresponding testsuite.
+ */
+ private Test fSuite;
+ /**
+ * Formatters from the command line.
+ */
+ private static Vector<JUnitResultFormatter> fgFromCmdLine = new Vector<>();
+ /**
+ * Holds the registered formatters.
+ */
+ private Vector<JUnitResultFormatter> formatters = new Vector<>();
+ /**
+ * Do we stop on errors.
+ */
+ private boolean fHaltOnError = false;
+ /**
+ * Do we stop on test failures.
+ */
+ private boolean fHaltOnFailure = false;
+ /**
+ * The TestSuite we are currently running.
+ */
+ private JUnitTest fJunitTest;
+ /**
+ * output written during the test
+ */
+ private PrintStream fSystemError;
+ /**
+ * Error output during the test
+ */
+ private PrintStream fSystemOut;
+ /**
+ * Exception caught in constructor.
+ */
+ private Exception fException;
+ /**
+ * Returncode
+ */
+ private int fRetCode = SUCCESS;
+
+ /**
* The main entry point (the parameters are not yet consistent with the Ant
* JUnitTestRunner, but eventually they should be). Parameters
*
* <pre>
- * -className=<testSuiteName>
- * -testPluginName<containingpluginName>
- * -formatter=<classname>(,<path>)
+ * -className: the name of the testSuite
+ * -testPluginName: the name of the containing plugin
+ * haltOnError: halt test on errors?
+ * haltOnFailure: halt test on failures?
+ * -testlistener listenerClass: deprecated
+ * print a warning that this option is deprecated
+ * formatter: a JUnitResultFormatter given as classname,filename.
+ * If filename is ommitted, System.out is assumed.
* </pre>
- * Where <classname> is the formatter classname, currently ignored as only
- * LegacyXmlResultFormatter is used. The path is either the path to the
- * result file and should include the file extension (xml) if a single test
- * is being run or should be the path to the result directory where result
- * files should be created if multiple tests are being run. If no path is
- * given, the standard output is used.
*/
public static void main(String[] args) throws IOException {
System.exit(run(args));
@@ -163,10 +222,13 @@
String classesNames = null;
String testPluginName = null;
String testPluginsNames = null;
- String resultPathString = null;
+ String formatterString = null;
String timeoutString = null;
String junitReportOutput = null;
+ boolean haltError = false;
+ boolean haltFail = false;
+
Properties props = new Properties();
int startArgs = 0;
@@ -200,19 +262,19 @@
junitReportOutput = args[i + 1];
i++;
} else if (args[i].startsWith("haltOnError=")) {
- System.err.println("The haltOnError option is no longer supported");
+ haltError = Project.toBoolean(args[i].substring(12));
} else if (args[i].startsWith("haltOnFailure=")) {
- System.err.println("The haltOnFailure option is no longer supported");
+ haltFail = Project.toBoolean(args[i].substring(14));
} else if (args[i].startsWith("formatter=")) {
- String formatterString = args[i].substring(10);
- int seperatorIndex = formatterString.indexOf(',');
- resultPathString = formatterString.substring(seperatorIndex + 1);
+ formatterString = args[i].substring(10);
} else if (args[i].startsWith("propsfile=")) {
try (FileInputStream in = new FileInputStream(args[i].substring(10))) {
props.load(in);
}
} else if (args[i].equals("-testlistener")) {
- System.err.println("The testlistener option is no longer supported");
+ System.err
+ .println("The -testlistener option is no longer supported\nuse the formatter= option instead");
+ return ERRORS;
} else if (args[i].equals("-timeout")) {
if (i < args.length - 1)
timeoutString = args[i + 1];
@@ -245,133 +307,44 @@
// names
String[] testPlugins = testPluginsNames.split(",");
String[] suiteClasses = classesNames.split(",");
+ try {
+ createAndStoreFormatter(formatterString, suiteClasses);
+ } catch (BuildException be) {
+ System.err.println(be.getMessage());
+ return ERRORS;
+ }
int returnCode = 0;
int j = 0;
- EclipseTestRunner runner = new EclipseTestRunner();
for (String oneClassName : suiteClasses) {
- int result = runner.runTests(props, testPlugins[j], oneClassName, resultPathString, true);
+ JUnitTest t = new JUnitTest(oneClassName);
+ t.setProperties(props);
+ EclipseTestRunner runner = new EclipseTestRunner(t, testPlugins[j], haltError, haltFail);
+ transferFormatters(runner, j);
+ runner.run();
j++;
- if(result != 0) {
- returnCode = result;
+ if (runner.getRetCode() != 0) {
+ returnCode = runner.getRetCode();
}
}
return returnCode;
}
+ try {
+ createAndStoreFormatter(formatterString);
+ } catch (BuildException be) {
+ System.err.println(be.getMessage());
+ return ERRORS;
+ }
if (className == null)
throw new IllegalArgumentException("Test class name not specified");
- EclipseTestRunner runner = new EclipseTestRunner();
- return runner.runTests(props, testPluginName, className, resultPathString, false);
- }
- private int runTests(Properties props, String testPluginName, String testClassName, String resultPath, boolean multiTest) {
- ClassLoader currentTCCL = Thread.currentThread().getContextClassLoader();
- ExecutionListener executionListener = new ExecutionListener();
- if(testPluginName == null) {
- testPluginName = ClassLoaderTools.getClassPlugin(testClassName);
- }
- if(testPluginName == null)
- throw new IllegalArgumentException("Test class not found");
- LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
- .selectors(selectClass(testClassName))
- .build();
+ JUnitTest t = new JUnitTest(className);
- try {
- Thread.currentThread().setContextClassLoader(ClassLoaderTools.getJUnit5Classloader(getPlatformEngines()));
- final Launcher launcher = LauncherFactory.create();
+ t.setProperties(props);
- Thread.currentThread().setContextClassLoader(ClassLoaderTools.getPluginClassLoader(testPluginName, currentTCCL));
- try(LegacyXmlResultFormatter legacyXmlResultFormatter = new LegacyXmlResultFormatter()){
- try (OutputStream fileOutputStream = getResultOutputStream(resultPath,testClassName,multiTest)){
- legacyXmlResultFormatter.setDestination(fileOutputStream);
- legacyXmlResultFormatter.setContext(new ExecutionContext(props));
- launcher.execute(request, legacyXmlResultFormatter, executionListener);
- }
- } catch (IOException e) {
- e.printStackTrace();
- return ERRORS;
- }
- } finally {
- Thread.currentThread().setContextClassLoader(currentTCCL);
- }
- return executionListener.didExecutionContainedFailures() ? FAILURES : SUCCESS;
- }
-
- private OutputStream getResultOutputStream(String resultPathString, String testClassName, boolean multiTest) throws IOException {
- if(resultPathString == null)
- return System.out;
- File resultFile;
- if(multiTest) {
- Path resultDirectoryPath = new Path(resultPathString);
- File testDirectory = resultDirectoryPath.toFile();
- if(!testDirectory.exists())
- testDirectory.mkdirs();
- resultFile = resultDirectoryPath.append("TEST-"+testClassName+".xml").toFile();
- }else {
- resultFile = new Path(resultPathString).toFile();
- File resultDirectory = resultFile.getParentFile();
- if(!resultDirectory.exists())
- resultDirectory.mkdirs();
- }
- if(!resultFile.exists()) {
- resultFile.createNewFile();
- }
- return new FileOutputStream(resultFile);
- }
-
-
- private List<String> getPlatformEngines(){
- List<String> platformEngines = new ArrayList<>();
- Bundle bundle = FrameworkUtil.getBundle(getClass());
- Bundle[] bundles = bundle.getBundleContext().getBundles();
- for (Bundle iBundle : bundles) {
- try {
- BundleWiring bundleWiring = Platform.getBundle(iBundle.getSymbolicName()).adapt(BundleWiring.class);
- Collection<String> listResources = bundleWiring.listResources("META-INF/services", "org.junit.platform.engine.TestEngine", BundleWiring.LISTRESOURCES_LOCAL);
- if (!listResources.isEmpty())
- platformEngines.add(iBundle.getSymbolicName());
- } catch (Exception e) {
- // check the next bundle
- }
- }
- return platformEngines;
- }
-
- private final class ExecutionListener implements TestExecutionListener {
- private boolean executionContainedFailures;
-
- public ExecutionListener() {
- this.executionContainedFailures = false;
- }
-
- public boolean didExecutionContainedFailures() {
- return executionContainedFailures;
- }
-
- @Override
- public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
- if(testExecutionResult.getStatus() == org.junit.platform.engine.TestExecutionResult.Status.FAILED) {
- executionContainedFailures = true;
- }
- }
- }
-
- private final class ExecutionContext implements TestExecutionContext {
-
- private final Properties props;
-
- ExecutionContext(Properties props) {
- this.props = props;
- }
-
- @Override
- public Properties getProperties() {
- return this.props;
- }
-
- @Override
- public Optional<Project> getProject() {
- return null;
- }
+ EclipseTestRunner runner = new EclipseTestRunner(t, testPluginName, haltError, haltFail);
+ transferFormatters(runner);
+ runner.run();
+ return runner.getRetCode();
}
/**
@@ -431,7 +404,7 @@
// Dump all stacks:
dumpStackTraces(num, System.err);
dumpStackTraces(num, System.out); // System.err could be blocked, see
- // https://bugs.eclipse.org/506304
+ // https://bugs.eclipse.org/506304
logStackTraces(num); // make this available in the log, see bug 533367
if (!dumpSwtDisplay(num)) {
@@ -522,7 +495,7 @@
dumpDisplayState(System.err);
dumpDisplayState(System.out); // System.err could be blocked, see
- // https://bugs.eclipse.org/506304
+ // https://bugs.eclipse.org/506304
// Take a screenshot:
GC gc = new GC(display);
@@ -579,6 +552,307 @@
}
}
+ public EclipseTestRunner(JUnitTest test, String testPluginName, boolean haltOnError, boolean haltOnFailure) {
+ fJunitTest = test;
+ fTestPluginName = testPluginName;
+ fHaltOnError = haltOnError;
+ fHaltOnFailure = haltOnFailure;
+
+ try {
+ fSuite = getTest(test.getName());
+ } catch (Exception e) {
+ fRetCode = ERRORS;
+ fException = e;
+ }
+ }
+
+ protected Test getTest(String suiteClassName) throws TestFailedException {
+ if (suiteClassName.isEmpty()) {
+ clearStatus();
+ return null;
+ }
+ Class<?> testClass = null;
+ try {
+ testClass = loadSuiteClass(suiteClassName);
+ } catch (ClassNotFoundException e) {
+ if (e.getCause() != null) {
+ runFailed(e.getCause());
+ }
+ String clazz = e.getMessage();
+ if (clazz == null)
+ clazz = suiteClassName;
+ runFailed("Class not found \"" + clazz + "\"");
+ return null;
+ } catch (Exception e) {
+ runFailed(e);
+ return null;
+ }
+ Method suiteMethod = null;
+ try {
+ suiteMethod = testClass.getMethod(SUITE_METHODNAME);
+ } catch (Exception e) {
+ // try to extract a test suite automatically
+ clearStatus();
+ return new junit.framework.JUnit4TestAdapter(testClass);
+ }
+ if (!Modifier.isStatic(suiteMethod.getModifiers())) {
+ runFailed("suite() method must be static");
+ return null;
+ }
+ Test test = null;
+ try {
+ test = (Test) suiteMethod.invoke(null); // static method
+ if (test == null)
+ return test;
+ } catch (InvocationTargetException e) {
+ runFailed("Failed to invoke suite():" + e.getTargetException().toString());
+ return null;
+ } catch (IllegalAccessException e) {
+ runFailed("Failed to invoke suite():" + e.toString());
+ return null;
+ }
+ clearStatus();
+ return test;
+ }
+
+ protected void runFailed(String message) throws TestFailedException {
+ System.err.println(message);
+ throw new TestFailedException(message);
+ }
+
+ protected void runFailed(Throwable e) throws TestFailedException {
+ e.printStackTrace();
+ throw new TestFailedException(e);
+ }
+
+ protected void clearStatus() {
+ }
+
+ /**
+ * Loads the class either with the system class loader or a plugin class loader
+ * if a plugin name was specified
+ */
+ protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
+ if (fTestPluginName == null)
+ return Class.forName(suiteClassName);
+ Bundle bundle = Platform.getBundle(fTestPluginName);
+ if (bundle == null) {
+ throw new ClassNotFoundException(suiteClassName,
+ new Exception("Could not find plugin \"" + fTestPluginName + "\""));
+ }
+
+ // is the plugin a fragment?
+ Dictionary<String, String> headers = bundle.getHeaders();
+ String hostHeader = headers.get(Constants.FRAGMENT_HOST);
+ if (hostHeader != null) {
+ // we are a fragment for sure
+ // we need to find which is our host
+ ManifestElement[] hostElement = null;
+ try {
+ hostElement = ManifestElement.parseHeader(Constants.FRAGMENT_HOST, hostHeader);
+ } catch (BundleException e) {
+ throw new RuntimeException("Could not find host for fragment:" + fTestPluginName, e);
+ }
+ Bundle host = Platform.getBundle(hostElement[0].getValue());
+ // we really want to get the host not the fragment
+ bundle = host;
+ }
+
+ return bundle.loadClass(suiteClassName);
+ }
+
+ public void run() {
+ fTestResult = new TestResult();
+ fTestResult.addListener(this);
+ for (int i = 0; i < formatters.size(); i++) {
+ fTestResult.addListener(formatters.elementAt(i));
+ }
+
+ long start = System.currentTimeMillis();
+ fireStartTestSuite();
+
+ if (fException != null) { // had an exception in the constructor
+ for (int i = 0; i < formatters.size(); i++) {
+ formatters.elementAt(i).addError(null, fException);
+ }
+ fJunitTest.setCounts(1, 0, 1);
+ fJunitTest.setRunTime(0);
+ } else {
+ ByteArrayOutputStream errStrm = new ByteArrayOutputStream();
+ fSystemError = new PrintStream(errStrm);
+
+ ByteArrayOutputStream outStrm = new ByteArrayOutputStream();
+ fSystemOut = new PrintStream(outStrm);
+
+ try {
+ // pm.snapshot(1); // before
+ fSuite.run(fTestResult);
+ } finally {
+ // pm.snapshot(2); // after
+ fSystemError.close();
+ fSystemError = null;
+ fSystemOut.close();
+ fSystemOut = null;
+ sendOutAndErr(new String(outStrm.toByteArray()), new String(errStrm.toByteArray()));
+ fJunitTest.setCounts(fTestResult.runCount(), fTestResult.failureCount(), fTestResult.errorCount());
+ fJunitTest.setRunTime(System.currentTimeMillis() - start);
+ }
+ }
+ fireEndTestSuite();
+
+ if (fRetCode != SUCCESS || fTestResult.errorCount() != 0) {
+ fRetCode = ERRORS;
+ } else if (fTestResult.failureCount() != 0) {
+ fRetCode = FAILURES;
+ }
+
+ // pm.upload(getClass().getName());
+ }
+
+ /**
+ * Returns what System.exit() would return in the standalone version.
+ *
+ * @return 2 if errors occurred, 1 if tests failed else 0.
+ */
+ public int getRetCode() {
+ return fRetCode;
+ }
+
+ @Override
+ public void startTest(Test t) {
+ }
+
+ @Override
+ public void endTest(Test test) {
+ }
+
+ @Override
+ public void addFailure(Test test, AssertionFailedError t) {
+ if (fHaltOnFailure) {
+ fTestResult.stop();
+ }
+ }
+
+ @Override
+ public void addError(Test test, Throwable t) {
+ if (fHaltOnError) {
+ fTestResult.stop();
+ }
+ }
+
+ private void fireStartTestSuite() {
+ for (int i = 0; i < formatters.size(); i++) {
+ formatters.elementAt(i).startTestSuite(fJunitTest);
+ }
+ }
+
+ private void fireEndTestSuite() {
+ for (int i = 0; i < formatters.size(); i++) {
+ formatters.elementAt(i).endTestSuite(fJunitTest);
+ }
+ }
+
+ public void addFormatter(JUnitResultFormatter f) {
+ formatters.addElement(f);
+ }
+
+ /**
+ * Line format is: formatter=<classname>(,<pathname>)?
+ */
+ private static void createAndStoreFormatter(String line) throws BuildException {
+ String formatterClassName = null;
+ File formatterFile = null;
+
+ int pos = line.indexOf(',');
+ if (pos == -1) {
+ formatterClassName = line;
+ } else {
+ formatterClassName = line.substring(0, pos);
+ formatterFile = new File(line.substring(pos + 1)); // the method is
+ // package
+ // visible
+ }
+ fgFromCmdLine.addElement(createFormatter(formatterClassName, formatterFile));
+ }
+
+ /**
+ * Line format is: formatter=<pathname>
+ */
+ private static void createAndStoreFormatter(String line, String... suiteClassesNames) throws BuildException {
+ String formatterClassName = null;
+ File formatterFile = null;
+
+ int pos = line.indexOf(',');
+ if (pos == -1) {
+ formatterClassName = line;
+ } else {
+ formatterClassName = line.substring(0, pos);
+ }
+ File outputDirectory = new File(line.substring(pos + 1));
+ outputDirectory.mkdir();
+ for (String suiteClassName : suiteClassesNames) {
+
+ String pathname = "TEST-" + suiteClassName + ".xml";
+ if (outputDirectory.exists()) {
+ pathname = outputDirectory.getAbsolutePath() + "/" + pathname;
+ }
+ formatterFile = new File(pathname);
+ fgFromCmdLine.addElement(createFormatter(formatterClassName, formatterFile));
+ }
+
+ }
+
+ private static void transferFormatters(EclipseTestRunner runner, int j) {
+ runner.addFormatter(fgFromCmdLine.elementAt(j));
+ }
+
+ private static void transferFormatters(EclipseTestRunner runner) {
+ for (int i = 0; i < fgFromCmdLine.size(); i++) {
+ runner.addFormatter(fgFromCmdLine.elementAt(i));
+ }
+ }
+
+ /*
+ * DUPLICATED from FormatterElement, since it is package visible only
+ */
+ private static JUnitResultFormatter createFormatter(String classname, File outfile) throws BuildException {
+ OutputStream out = System.out;
+
+ if (classname == null) {
+ throw new BuildException("you must specify type or classname");
+ }
+ Class<?> f = null;
+ try {
+ f = EclipseTestRunner.class.getClassLoader().loadClass(classname);
+ } catch (ClassNotFoundException e) {
+ throw new BuildException(e);
+ }
+
+ Object o = null;
+ try {
+ o = f.getDeclaredConstructor().newInstance();
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
+ | NoSuchMethodException | SecurityException e) {
+ throw new BuildException(e);
+ }
+
+ if (!(o instanceof JUnitResultFormatter)) {
+ throw new BuildException(classname + " is not a JUnitResultFormatter");
+ }
+
+ JUnitResultFormatter r = (JUnitResultFormatter) o;
+
+ if (outfile != null) {
+ try {
+ out = new FileOutputStream(outfile);
+ } catch (java.io.IOException e) {
+ throw new BuildException(e);
+ }
+ }
+ r.setOutput(out);
+ return r;
+ }
+
public static void dumpAwtScreenshot(String screenshotFile) {
try {
URL location = AwtScreenshot.class.getProtectionDomain().getCodeSource().getLocation();
@@ -622,4 +896,23 @@
e.printStackTrace();
}
}
+
+ private void sendOutAndErr(String out, String err) {
+ for (JUnitResultFormatter formatter : formatters) {
+ formatter.setSystemOutput(out);
+ formatter.setSystemError(err);
+ }
+ }
+
+ protected void handleOutput(String line) {
+ if (fSystemOut != null) {
+ fSystemOut.println(line);
+ }
+ }
+
+ protected void handleErrorOutput(String line) {
+ if (fSystemError != null) {
+ fSystemError.println(line);
+ }
+ }
}
diff --git a/bundles/org.eclipse.test/src/org/eclipse/test/LegacyXmlResultFormatter.java b/bundles/org.eclipse.test/src/org/eclipse/test/LegacyXmlResultFormatter.java
deleted file mode 100644
index 31e1da3..0000000
--- a/bundles/org.eclipse.test/src/org/eclipse/test/LegacyXmlResultFormatter.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2018 Red Hat Inc. and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * Lucas Bullen (Red Hat Inc.) - initial API and implementation
- *******************************************************************************/
-package org.eclipse.test;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.util.Date;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-import javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-
-import org.apache.tools.ant.taskdefs.optional.junitlauncher.TestResultFormatter;
-import org.apache.tools.ant.util.DOMElementWriter;
-import org.apache.tools.ant.util.DateUtils;
-import org.junit.platform.commons.util.ExceptionUtils;
-import org.junit.platform.engine.TestExecutionResult;
-import org.junit.platform.engine.TestSource;
-import org.junit.platform.engine.reporting.ReportEntry;
-import org.junit.platform.engine.support.descriptor.ClassSource;
-import org.junit.platform.launcher.TestIdentifier;
-import org.junit.platform.launcher.TestPlan;
-
-/**
- * A {@link TestResultFormatter} which generates an XML report of the tests. The generated XML reports
- * conforms to the schema of the XML that was generated by the {@code junit} task's XML
- * report formatter and can be used by the {@code junitreport} task
- */
-public class LegacyXmlResultFormatter extends AbstractJUnitResultFormatter {
-
- private static final double ONE_SECOND = 1000.0;
-
- OutputStream outputStream;
- final Map<TestIdentifier, Stats> testIds = new ConcurrentHashMap<>();
- final Map<TestIdentifier, Optional<String>> skipped = new ConcurrentHashMap<>();
- final Map<TestIdentifier, Optional<Throwable>> failed = new ConcurrentHashMap<>();
- final Map<TestIdentifier, Optional<Throwable>> aborted = new ConcurrentHashMap<>();
-
- TestPlan testPlan;
- long testPlanStartedAt = -1;
- long testPlanEndedAt = -1;
- final AtomicLong numTestsRun = new AtomicLong(0);
- final AtomicLong numTestsFailed = new AtomicLong(0);
- final AtomicLong numTestsSkipped = new AtomicLong(0);
- final AtomicLong numTestsAborted = new AtomicLong(0);
-
-
- @Override
- public void testPlanExecutionStarted(final TestPlan plan) {
- this.testPlan = plan;
- this.testPlanStartedAt = System.currentTimeMillis();
- }
-
- @Override
- public void testPlanExecutionFinished(final TestPlan plan) {
- this.testPlanEndedAt = System.currentTimeMillis();
- // format and print out the result
- try {
- new XMLReportWriter().write();
- } catch (IOException | XMLStreamException e) {
- handleException(e);
- return;
- }
- }
-
- @Override
- public void dynamicTestRegistered(final TestIdentifier testIdentifier) {
- // nothing to do
- }
-
- @Override
- public void executionSkipped(final TestIdentifier testIdentifier, final String reason) {
- final long currentTime = System.currentTimeMillis();
- this.numTestsSkipped.incrementAndGet();
- this.skipped.put(testIdentifier, Optional.ofNullable(reason));
- // a skipped test is considered started and ended now
- final Stats stats = new Stats(testIdentifier, currentTime);
- stats.endedAt = currentTime;
- this.testIds.put(testIdentifier, stats);
- }
-
- @Override
- public void executionStarted(final TestIdentifier testIdentifier) {
- final long currentTime = System.currentTimeMillis();
- this.testIds.putIfAbsent(testIdentifier, new Stats(testIdentifier, currentTime));
- if (testIdentifier.isTest()) {
- this.numTestsRun.incrementAndGet();
- }
- }
-
- @Override
- public void executionFinished(final TestIdentifier testIdentifier, final TestExecutionResult testExecutionResult) {
- final long currentTime = System.currentTimeMillis();
- final Stats stats = this.testIds.get(testIdentifier);
- if (stats != null) {
- stats.endedAt = currentTime;
- }
- switch (testExecutionResult.getStatus()) {
- case SUCCESSFUL: {
- break;
- }
- case ABORTED: {
- this.numTestsAborted.incrementAndGet();
- this.aborted.put(testIdentifier, testExecutionResult.getThrowable());
- break;
- }
- case FAILED: {
- this.numTestsFailed.incrementAndGet();
- this.failed.put(testIdentifier, testExecutionResult.getThrowable());
- break;
- }
- }
- }
-
- @Override
- public void reportingEntryPublished(final TestIdentifier testIdentifier, final ReportEntry entry) {
- // nothing to do
- }
-
- @Override
- public void setDestination(final OutputStream os) {
- this.outputStream = os;
- }
-
- private final class Stats {
- final long startedAt;
- long endedAt;
-
- Stats(final TestIdentifier testIdentifier, final long startedAt) {
- this.startedAt = startedAt;
- }
- }
-
- private final class XMLReportWriter {
-
- private static final String ELEM_TESTSUITE = "testsuite";
- private static final String ELEM_PROPERTIES = "properties";
- private static final String ELEM_PROPERTY = "property";
- private static final String ELEM_TESTCASE = "testcase";
- private static final String ELEM_SKIPPED = "skipped";
- private static final String ELEM_FAILURE = "failure";
- private static final String ELEM_ABORTED = "aborted";
- private static final String ELEM_SYSTEM_OUT = "system-out";
- private static final String ELEM_SYSTEM_ERR = "system-err";
-
-
- private static final String ATTR_CLASSNAME = "classname";
- private static final String ATTR_NAME = "name";
- private static final String ATTR_VALUE = "value";
- private static final String ATTR_TIME = "time";
- private static final String ATTR_TIMESTAMP = "timestamp";
- private static final String ATTR_NUM_ABORTED = "aborted";
- private static final String ATTR_NUM_FAILURES = "failures";
- private static final String ATTR_NUM_TESTS = "tests";
- private static final String ATTR_NUM_SKIPPED = "skipped";
- private static final String ATTR_MESSAGE = "message";
- private static final String ATTR_TYPE = "type";
-
- public XMLReportWriter() {
- // TODO Auto-generated constructor stub
- }
-
- void write() throws XMLStreamException, IOException {
- final XMLStreamWriter writer = XMLOutputFactory.newFactory().createXMLStreamWriter(outputStream, "UTF-8");
- try {
- writer.writeStartDocument();
- writeTestSuite(writer);
- writer.writeEndDocument();
- } finally {
- writer.close();
- }
- }
-
- void writeTestSuite(final XMLStreamWriter writer) throws XMLStreamException, IOException {
- // write the testsuite element
- writer.writeStartElement(ELEM_TESTSUITE);
- final String testsuiteName = determineTestSuiteName();
- writer.writeAttribute(ATTR_NAME, testsuiteName);
- // time taken for the tests execution
- writer.writeAttribute(ATTR_TIME, String.valueOf((testPlanEndedAt - testPlanStartedAt) / ONE_SECOND));
- // add the timestamp of report generation
- final String timestamp = DateUtils.format(new Date(), DateUtils.ISO8601_DATETIME_PATTERN);
- writer.writeAttribute(ATTR_TIMESTAMP, timestamp);
- writer.writeAttribute(ATTR_NUM_TESTS, String.valueOf(numTestsRun.longValue()));
- writer.writeAttribute(ATTR_NUM_FAILURES, String.valueOf(numTestsFailed.longValue()));
- writer.writeAttribute(ATTR_NUM_SKIPPED, String.valueOf(numTestsSkipped.longValue()));
- writer.writeAttribute(ATTR_NUM_ABORTED, String.valueOf(numTestsAborted.longValue()));
-
- // write the properties
- writeProperties(writer);
- // write the tests
- writeTestCase(writer);
- writeSysOut(writer);
- writeSysErr(writer);
- // end the testsuite
- writer.writeEndElement();
- }
-
- void writeProperties(final XMLStreamWriter writer) throws XMLStreamException {
- final Properties properties = LegacyXmlResultFormatter.this.context.getProperties();
- if (properties == null || properties.isEmpty()) {
- return;
- }
- writer.writeStartElement(ELEM_PROPERTIES);
- for (final String prop : properties.stringPropertyNames()) {
- writer.writeStartElement(ELEM_PROPERTY);
- writer.writeAttribute(ATTR_NAME, prop);
- writer.writeAttribute(ATTR_VALUE, properties.getProperty(prop));
- writer.writeEndElement();
- }
- writer.writeEndElement();
- }
-
- void writeTestCase(final XMLStreamWriter writer) throws XMLStreamException {
- for (final Map.Entry<TestIdentifier, Stats> entry : testIds.entrySet()) {
- final TestIdentifier testId = entry.getKey();
- if (!testId.isTest()) {
- // only interested in test methods
- continue;
- }
- // find the parent class of this test method
- final Optional<TestIdentifier> parent = testPlan.getParent(testId);
- if (!parent.isPresent()) {
- continue;
- }
- final String classname = parent.get().getLegacyReportingName();
- writer.writeStartElement(ELEM_TESTCASE);
- writer.writeAttribute(ATTR_CLASSNAME, classname);
- writer.writeAttribute(ATTR_NAME, testId.getDisplayName());
- final Stats stats = entry.getValue();
- writer.writeAttribute(ATTR_TIME, String.valueOf((stats.endedAt - stats.startedAt) / ONE_SECOND));
- // skipped element if the test was skipped
- writeSkipped(writer, testId);
- // failed element if the test failed
- writeFailed(writer, testId);
- // aborted element if the test was aborted
- writeAborted(writer, testId);
-
- writer.writeEndElement();
- }
- }
-
- private void writeSkipped(final XMLStreamWriter writer, final TestIdentifier testIdentifier) throws XMLStreamException {
- if (!skipped.containsKey(testIdentifier)) {
- return;
- }
- writer.writeStartElement(ELEM_SKIPPED);
- final Optional<String> reason = skipped.get(testIdentifier);
- if (reason.isPresent()) {
- writer.writeAttribute(ATTR_MESSAGE, reason.get());
- }
- writer.writeEndElement();
- }
-
- private void writeFailed(final XMLStreamWriter writer, final TestIdentifier testIdentifier) throws XMLStreamException {
- if (!failed.containsKey(testIdentifier)) {
- return;
- }
- writer.writeStartElement(ELEM_FAILURE);
- final Optional<Throwable> cause = failed.get(testIdentifier);
- if (cause.isPresent()) {
- final Throwable t = cause.get();
- final String message = t.getMessage();
- if (message != null && !message.trim().isEmpty()) {
- writer.writeAttribute(ATTR_MESSAGE, message);
- }
- writer.writeAttribute(ATTR_TYPE, t.getClass().getName());
- writer.writeCharacters(ExceptionUtils.readStackTrace(t));
- }
- writer.writeEndElement();
- }
-
- private void writeAborted(final XMLStreamWriter writer, final TestIdentifier testIdentifier) throws XMLStreamException {
- if (!aborted.containsKey(testIdentifier)) {
- return;
- }
- writer.writeStartElement(ELEM_ABORTED);
- final Optional<Throwable> cause = aborted.get(testIdentifier);
- if (cause.isPresent()) {
- final Throwable t = cause.get();
- final String message = t.getMessage();
- if (message != null && !message.trim().isEmpty()) {
- writer.writeAttribute(ATTR_MESSAGE, message);
- }
- writer.writeAttribute(ATTR_TYPE, t.getClass().getName());
- }
- writer.writeEndElement();
- }
-
- private void writeSysOut(final XMLStreamWriter writer) throws XMLStreamException, IOException {
- if (!LegacyXmlResultFormatter.this.hasSysOut()) {
- return;
- }
- writer.writeStartElement(ELEM_SYSTEM_OUT);
- try (final Reader reader = LegacyXmlResultFormatter.this.getSysOutReader()) {
- writeCharactersFrom(reader, writer);
- }
- writer.writeEndElement();
- }
-
- private void writeSysErr(final XMLStreamWriter writer) throws XMLStreamException, IOException {
- if (!LegacyXmlResultFormatter.this.hasSysErr()) {
- return;
- }
- writer.writeStartElement(ELEM_SYSTEM_ERR);
- try (final Reader reader = LegacyXmlResultFormatter.this.getSysErrReader()) {
- writeCharactersFrom(reader, writer);
- }
- writer.writeEndElement();
- }
-
- private void writeCharactersFrom(final Reader reader, final XMLStreamWriter writer) throws IOException, XMLStreamException {
- final char[] chars = new char[1024];
- int numRead = -1;
- while ((numRead = reader.read(chars)) != -1) {
- // although it's called a DOMElementWriter, the encode method is just a
- // straight forward XML util method which doesn't concern about whether
- // DOM, SAX, StAX semantics.
- // TODO: Perhaps make it a static method
- final String encoded = new DOMElementWriter().encode(new String(chars, 0, numRead));
- writer.writeCharacters(encoded);
- }
- }
-
- private String determineTestSuiteName() {
- // this is really a hack to try and match the expectations of the XML report in JUnit4.x
- // world. In JUnit5, the TestPlan doesn't have a name and a TestPlan (for which this is a
- // listener) can have numerous tests within it
- final Set<TestIdentifier> roots = testPlan.getRoots();
- if (roots.isEmpty()) {
- return "UNKNOWN";
- }
- for (final TestIdentifier root : roots) {
- final Optional<ClassSource> classSource = findFirstClassSource(root);
- if (classSource.isPresent()) {
- return classSource.get().getClassName();
- }
- }
- return "UNKNOWN";
- }
-
- private Optional<ClassSource> findFirstClassSource(final TestIdentifier root) {
- if (root.getSource().isPresent()) {
- final TestSource source = root.getSource().get();
- if (source instanceof ClassSource) {
- return Optional.of((ClassSource) source);
- }
- }
- for (final TestIdentifier child : testPlan.getChildren(root)) {
- final Optional<ClassSource> classSource = findFirstClassSource(child);
- if (classSource.isPresent()) {
- return classSource;
- }
- }
- return Optional.empty();
- }
- }
-
-}
diff --git a/bundles/org.eclipse.test/src/org/eclipse/test/UITestApplication.java b/bundles/org.eclipse.test/src/org/eclipse/test/UITestApplication.java
index 62b1288..966b0d0 100644
--- a/bundles/org.eclipse.test/src/org/eclipse/test/UITestApplication.java
+++ b/bundles/org.eclipse.test/src/org/eclipse/test/UITestApplication.java
@@ -10,17 +10,19 @@
*******************************************************************************/
package org.eclipse.test;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
import java.io.IOException;
+import junit.framework.Assert;
+
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IPlatformRunnable;
import org.eclipse.core.runtime.Platform;
-import org.eclipse.equinox.app.IApplication;
-import org.eclipse.equinox.app.IApplicationContext;
+
import org.eclipse.ui.IWindowListener;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
@@ -30,27 +32,27 @@
/**
* A Workbench that runs a test suite specified in the command line arguments.
- *
+ *
* @deprecated As using deprecated materials
- */
+ */
@Deprecated
public class UITestApplication implements IPlatformRunnable, ITestHarness, IApplication {
private static final String DEFAULT_APP_3_0 = "org.eclipse.ui.ide.workbench"; //$NON-NLS-1$
private static final String DEFAULT_APP_PRE_3_0 = "org.eclipse.ui.workbench"; //$NON-NLS-1$
-
+
private boolean fInDeprecatedMode = false;
private TestableObject fTestableObject;
int fTestRunnerResult = -1;
private IApplicationContext appContext;
-
-
+
+
@Override
public Object run(final Object args) throws Exception {
// Get the application to test
Object application = getApplication((String[])args);
- assertNotNull(application);
-
+ Assert.assertNotNull(application);
+
Object result;
if (fInDeprecatedMode && (application instanceof IPlatformRunnable)) {
result = runDeprecatedApplication((IPlatformRunnable)application, args);
@@ -63,8 +65,8 @@
}
return Integer.valueOf(fTestRunnerResult);
}
-
-
+
+
/*
* return the application to run, or null if not even the default application
* is found.
@@ -75,11 +77,11 @@
// If no application is specified, the 3.0 default workbench application
// is returned.
IExtension extension =
- Platform.getExtensionRegistry().getExtension(
- Platform.PI_RUNTIME,
- Platform.PT_APPLICATIONS,
- getApplicationToRun(args));
-
+ Platform.getExtensionRegistry().getExtension(
+ Platform.PI_RUNTIME,
+ Platform.PT_APPLICATIONS,
+ getApplicationToRun(args));
+
// If no 3.0 extension can be found, search the registry
// for the pre-3.0 default workbench application, i.e. org.eclipse ui.workbench
// Set the deprecated flag to true
@@ -90,9 +92,9 @@
DEFAULT_APP_PRE_3_0);
fInDeprecatedMode = true;
}
-
- assertNotNull(extension);
-
+
+ Assert.assertNotNull(extension);
+
// If the extension does not have the correct grammar, return null.
// Otherwise, return the application object.
IConfigurationElement[] elements = extension.getConfigurationElements();
@@ -108,13 +110,13 @@
}
return null;
}
-
+
/**
* The -testApplication argument specifies the application to be run.
* If the PDE JUnit launcher did not set this argument, then return
* the name of the default application.
* In 3.0, the default is the "org.eclipse.ui.ide.worbench" application.
- *
+ *
*/
private String getApplicationToRun(String[] args) {
for (int i = 0; i < args.length; i++) {
@@ -123,21 +125,21 @@
}
return DEFAULT_APP_3_0;
}
-
+
/**
* In 3.0 mode
- *
+ *
*/
private Object runApplication(Object application, Object args) throws Exception {
fTestableObject = PlatformUI.getTestableObject();
fTestableObject.setTestHarness(this);
if (application instanceof IPlatformRunnable) {
return ((IPlatformRunnable) application).run(args);
- }
+ }
return ((IApplication) application).start(appContext);
-
+
}
-
+
/*
* If we are in pre-3.0 mode, then the application to run is
* "org.eclipse.ui.workbench" Therefore, we safely cast the runnable object
@@ -146,11 +148,11 @@
* done, we explicitly call close() on the workbench.
*/
private Object runDeprecatedApplication(
- IPlatformRunnable object,
- final Object args)
- throws Exception {
+ IPlatformRunnable object,
+ final Object args)
+ throws Exception {
- assertNotNull(object instanceof IWorkbench);
+ Assert.assertTrue(object instanceof IWorkbench);
final IWorkbench workbench = (IWorkbench) object;
// the 'started' flag is used so that we only run tests when the window
@@ -212,8 +214,8 @@
@Override
public void stop() {
// TODO Auto-generated method stub
-
+
}
-
+
}