| /******************************************************************************* |
| * 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); |
| } |
| }); |
| } |
| } |