blob: 72aa6076124fcf18477f754c55d0ed35896560b3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2015 Anton Gorenkov.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Anton Gorenkov - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.testsrunner.launcher;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.testsrunner.internal.TestsRunnerPlugin;
import org.eclipse.cdt.testsrunner.internal.launcher.ITestsLaunchConfigurationConstants;
import org.eclipse.cdt.testsrunner.internal.launcher.LauncherMessages;
import org.eclipse.cdt.testsrunner.internal.launcher.TestsRunnerProviderInfo;
import org.eclipse.cdt.testsrunner.internal.ui.view.TestPathUtils;
import org.eclipse.cdt.testsrunner.model.TestingException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchDelegate;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.ILaunchConfigurationDelegate2;
import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
/**
* Launch delegate implementation that redirects its queries to the preferred
* launch delegate, correcting the arguments attribute (to take into account
* auto generated test module parameters) and setting up the custom process
* factory (to handle testing process IO streams).
*/
public abstract class BaseTestsLaunchDelegate extends LaunchConfigurationDelegate {
/** Stores the changes made to the launch configuration. */
private Map<String, String> changesToLaunchConfiguration = new HashMap<>();
@Override
public ILaunch getLaunch(ILaunchConfiguration config, String mode) throws CoreException {
return getPreferredDelegate(config, mode).getLaunch(config, mode);
}
@Override
public boolean buildForLaunch(ILaunchConfiguration config, String mode, IProgressMonitor monitor)
throws CoreException {
return getPreferredDelegate(config, mode).buildForLaunch(config, mode, monitor);
}
@Override
public boolean finalLaunchCheck(ILaunchConfiguration config, String mode, IProgressMonitor monitor)
throws CoreException {
return getPreferredDelegate(config, mode).finalLaunchCheck(config, mode, monitor);
}
@Override
public boolean preLaunchCheck(ILaunchConfiguration config, String mode, IProgressMonitor monitor)
throws CoreException {
return getPreferredDelegate(config, mode).preLaunchCheck(config, mode, monitor);
}
@Override
public void launch(ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor)
throws CoreException {
if (mode.equals(ILaunchManager.RUN_MODE) || mode.equals(ILaunchManager.DEBUG_MODE)) {
// NOTE: The modified working copy of launch configuration cannot be passed directly
// to the preferred delegate because in this case the LaunchHistory will not work
// properly (and the rerun last launched configuration action will fail). So we
// just modify the existing configuration and revert all the changes back after
// the launch is done.
try {
// Changes launch configuration a bit and redirect it to the preferred C/C++ Application Launch delegate
updatedLaunchConfiguration(config);
getPreferredDelegate(config, mode).launch(config, mode, launch, monitor);
} finally {
revertChangedToLaunchConfiguration(config);
}
activateTestingView();
}
}
/**
* Revert the changes to launch configuration previously made with
* <code>updatedLaunchConfigurationAttribute()</code>.
*
* @param config launch configuration to revert
*/
private void revertChangedToLaunchConfiguration(ILaunchConfiguration config) throws CoreException {
ILaunchConfigurationWorkingCopy configWC = config.getWorkingCopy();
for (Map.Entry<String, String> changeEntry : changesToLaunchConfiguration.entrySet()) {
configWC.setAttribute(changeEntry.getKey(), changeEntry.getValue());
}
configWC.doSave();
changesToLaunchConfiguration.clear();
}
/**
* Saves the current value of the specified attribute (to be reverted later)
* and update its value in launch configuration.
*
* @param config launch configuration which attribute should be updated
* @param attributeName attribute name
* @param value new value of the specified attribute
*/
private void updatedLaunchConfigurationAttribute(ILaunchConfigurationWorkingCopy config, String attributeName,
String value) throws CoreException {
changesToLaunchConfiguration.put(attributeName, config.getAttribute(attributeName, "")); //$NON-NLS-1$
config.setAttribute(attributeName, value);
}
/**
* Makes the necessary changes to the launch configuration before passing it
* to the underlying delegate. Currently, updates the program arguments with
* the value that was obtained from Tests Runner provider plug-in.
*
* @param config launch configuration
*/
private void updatedLaunchConfiguration(ILaunchConfiguration config) throws CoreException {
changesToLaunchConfiguration.clear();
ILaunchConfigurationWorkingCopy configWC = config.getWorkingCopy();
setProgramArguments(configWC);
configWC.doSave();
}
/**
* Updates the program arguments with the value that was obtained from Tests
* Runner provider plug-in.
*
* @param config launch configuration
*/
private void setProgramArguments(ILaunchConfigurationWorkingCopy config) throws CoreException {
List<?> packedTestsFilter = config.getAttribute(ITestsLaunchConfigurationConstants.ATTR_TESTS_FILTER,
Collections.EMPTY_LIST);
String[][] testsFilter = TestPathUtils
.unpackTestPaths(packedTestsFilter.toArray(new String[packedTestsFilter.size()]));
// Configure test module run parameters with a Tests Runner
String[] params = null;
try {
params = getTestsRunner(config).getAdditionalLaunchParameters(testsFilter);
} catch (TestingException e) {
throw new CoreException(
new Status(IStatus.ERROR, TestsRunnerPlugin.getUniqueIdentifier(), e.getLocalizedMessage(), null));
}
// Rewrite ATTR_PROGRAM_ARGUMENTS attribute of launch configuration
if (params != null && params.length >= 1) {
StringBuilder sb = new StringBuilder();
sb.append(config.getAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, "")); //$NON-NLS-1$
for (String param : params) {
sb.append(' ');
sb.append(param);
}
updatedLaunchConfigurationAttribute(config, ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
sb.toString());
}
}
/**
* Resolves Tests Runner provider plug-in interface by the value written in
* launch configuration.
*
* @param config launch configuration
*/
private ITestsRunnerProvider getTestsRunner(ILaunchConfiguration config) throws CoreException {
TestsRunnerProviderInfo testsRunnerProviderInfo = TestsRunnerPlugin.getDefault()
.getTestsRunnerProvidersManager().getTestsRunnerProviderInfo(config);
if (testsRunnerProviderInfo == null) {
throw new CoreException(new Status(IStatus.ERROR, TestsRunnerPlugin.getUniqueIdentifier(),
LauncherMessages.BaseTestsLaunchDelegate_invalid_tests_runner, null));
}
ITestsRunnerProvider testsRunnerProvider = testsRunnerProviderInfo.instantiateTestsRunnerProvider();
if (testsRunnerProvider == null) {
throw new CoreException(new Status(IStatus.ERROR, TestsRunnerPlugin.getUniqueIdentifier(),
LauncherMessages.BaseTestsLaunchDelegate_tests_runner_load_failed, null));
}
return testsRunnerProvider;
}
/**
* Resolves the preferred launch delegate for the specified configuration to
* launch C/C++ Local Application in the specified mode. The preferred
* launch delegate ID is taken from <code>getPreferredDelegateId()</code>.
*
* @param config launch configuration
* @param mode mode
* @return launch delegate
*/
private ILaunchConfigurationDelegate2 getPreferredDelegate(ILaunchConfiguration config, String mode)
throws CoreException {
ILaunchManager launchMgr = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationType localCfg = launchMgr
.getLaunchConfigurationType(ICDTLaunchConfigurationConstants.ID_LAUNCH_C_APP);
Set<String> modes = config.getModes();
modes.add(mode);
String preferredDelegateId = getPreferredDelegateId();
for (ILaunchDelegate delegate : localCfg.getDelegates(modes)) {
if (preferredDelegateId.equals(delegate.getId())) {
return (ILaunchConfigurationDelegate2) delegate.getDelegate();
}
}
return null;
}
/**
* Returns the launch delegate id which should be used to redirect the
* launch.
*
* @return launch delegate ID
*/
public abstract String getPreferredDelegateId();
/**
* Activates the view showing testing results.
*/
private void activateTestingView() {
Display.getDefault().syncExec(() -> {
try {
IWorkbenchWindow activeWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IViewPart view = activeWindow.getActivePage()
.showView(ITestsRunnerConstants.TESTS_RUNNER_RESULTS_VIEW_ID);
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().activate(view);
} catch (PartInitException e) {
TestsRunnerPlugin.log(e);
}
});
}
}