/*
* Copyright 2015-2017 the original author or authors.
*
* 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
*/
package org.junit.platform.console.tasks;
import static org.junit.platform.commons.meta.API.Usage.Internal;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import org.junit.platform.commons.JUnitException;
import org.junit.platform.commons.meta.API;
import org.junit.platform.commons.util.ClassLoaderUtils;
import org.junit.platform.console.options.CommandLineOptions;
import org.junit.platform.console.options.Details;
import org.junit.platform.console.options.Theme;
import org.junit.platform.launcher.Launcher;
import org.junit.platform.launcher.LauncherDiscoveryRequest;
import org.junit.platform.launcher.TestExecutionListener;
import org.junit.platform.launcher.core.LauncherFactory;
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
import org.junit.platform.launcher.listeners.TestExecutionSummary;
/**
* @since 1.0
*/
@API(Internal)
public class ConsoleTestExecutor {
private final CommandLineOptions options;
private final Supplier<Launcher> launcherSupplier;
public ConsoleTestExecutor(CommandLineOptions options) {
this(options, LauncherFactory::create);
}
// for tests only
ConsoleTestExecutor(CommandLineOptions options, Supplier<Launcher> launcherSupplier) {
this.options = options;
this.launcherSupplier = launcherSupplier;
}
public TestExecutionSummary execute(PrintWriter out) throws Exception {
return new CustomContextClassLoaderExecutor(createCustomClassLoader()).invoke(() -> executeTests(out));
}
private TestExecutionSummary executeTests(PrintWriter out) {
Launcher launcher = launcherSupplier.get();
SummaryGeneratingListener summaryListener = registerListeners(out, launcher);
LauncherDiscoveryRequest discoveryRequest = new DiscoveryRequestCreator().toDiscoveryRequest(options);
launcher.execute(discoveryRequest);
TestExecutionSummary summary = summaryListener.getSummary();
printSummary(summary, out);
return summary;
}
private Optional<ClassLoader> createCustomClassLoader() {
List<Path> additionalClasspathEntries = options.getAdditionalClasspathEntries();
if (!additionalClasspathEntries.isEmpty()) {
URL[] urls = additionalClasspathEntries.stream().map(this::toURL).toArray(URL[]::new);
ClassLoader parentClassLoader = ClassLoaderUtils.getDefaultClassLoader();
ClassLoader customClassLoader = URLClassLoader.newInstance(urls, parentClassLoader);
return Optional.of(customClassLoader);
}
return Optional.empty();
}
private URL toURL(Path path) {
try {
return path.toUri().toURL();
}
catch (Exception ex) {
throw new JUnitException("Invalid classpath entry: " + path, ex);
}
}
private SummaryGeneratingListener registerListeners(PrintWriter out, Launcher launcher) {
// always register summary generating listener
SummaryGeneratingListener summaryListener = new SummaryGeneratingListener();
launcher.registerTestExecutionListeners(summaryListener);
// optionally, register test plan execution details printing listener
createDetailsPrintingListener(out).ifPresent(launcher::registerTestExecutionListeners);
// optionally, register XML reports writing listener
createXmlWritingListener(out).ifPresent(launcher::registerTestExecutionListeners);
return summaryListener;
}
private Optional<TestExecutionListener> createDetailsPrintingListener(PrintWriter out) {
boolean disableAnsiColors = options.isAnsiColorOutputDisabled();
Theme theme = options.getTheme();
switch (options.getDetails()) {
case FLAT:
return Optional.of(new FlatPrintingListener(out, disableAnsiColors));
case TREE:
return Optional.of(new TreePrintingListener(out, disableAnsiColors, theme));
case VERBOSE:
return Optional.of(new VerboseTreePrintingListener(out, disableAnsiColors, 16, theme));
default:
return Optional.empty();
}
}
private Optional<TestExecutionListener> createXmlWritingListener(PrintWriter out) {
if (options.getReportsDir().isPresent()) {
return Optional.of(new XmlReportsWritingListener(options.getReportsDir().get(), out));
}
return Optional.empty();
}
private void printSummary(TestExecutionSummary summary, PrintWriter out) {
// Otherwise the failures have already been printed in detail
if (EnumSet.of(Details.NONE, Details.TREE).contains(options.getDetails())) {
summary.printFailuresTo(out);
}
summary.printTo(out);
}
}