From 92b20bb5b91f70f7b40cb51eda96c39ef099975b Mon Sep 17 00:00:00 2001 From: fedejeanne Date: Tue, 14 Nov 2023 16:29:46 +0100 Subject: [PATCH] Call the "activated" method of the default tab in a Launch Config Dialog Also add a new test bundle that contains the proper regression test. Bundle: org.eclipse.debug.ui.tests Class: LaunchConfigurationTabGroupViewerTest This class also contains a regression test for https://github.com/eclipse-platform/eclipse.platform/pull/766 Fixes: https://github.com/eclipse-platform/eclipse.platform/issues/859 --- .../META-INF/MANIFEST.MF | 2 + .../org.eclipse.debug.tests/plugin.properties | 1 + debug/org.eclipse.debug.tests/plugin.xml | 26 ++- .../eclipse/debug/tests/AutomatedSuite.java | 3 + ...LaunchConfigurationTabGroupViewerTest.java | 158 ++++++++++++++++++ .../ui/launchconfigurations/tabs/SpyTab.java | 62 +++++++ .../tabs/SpyTabGroup.java | 17 ++ .../LaunchConfigurationTabGroupViewer.java | 43 +++-- 8 files changed, 298 insertions(+), 14 deletions(-) create mode 100644 debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/LaunchConfigurationTabGroupViewerTest.java create mode 100644 debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/tabs/SpyTab.java create mode 100644 debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/tabs/SpyTabGroup.java diff --git a/debug/org.eclipse.debug.tests/META-INF/MANIFEST.MF b/debug/org.eclipse.debug.tests/META-INF/MANIFEST.MF index ea7fdc95d93..555e9f977d5 100644 --- a/debug/org.eclipse.debug.tests/META-INF/MANIFEST.MF +++ b/debug/org.eclipse.debug.tests/META-INF/MANIFEST.MF @@ -27,6 +27,8 @@ Export-Package: org.eclipse.debug.tests, org.eclipse.debug.tests.statushandlers, org.eclipse.debug.tests.stepfilters, org.eclipse.debug.tests.ui, + org.eclipse.debug.tests.ui.launchconfigurations, + org.eclipse.debug.tests.ui.launchconfigurations.tabs, org.eclipse.debug.tests.view.memory, org.eclipse.debug.tests.viewer.model Eclipse-BundleShape: dir diff --git a/debug/org.eclipse.debug.tests/plugin.properties b/debug/org.eclipse.debug.tests/plugin.properties index 56ca2e3b1bb..6d8239d8517 100755 --- a/debug/org.eclipse.debug.tests/plugin.properties +++ b/debug/org.eclipse.debug.tests/plugin.properties @@ -22,4 +22,5 @@ launchConfigurationType.name = Test Launch Type extension.name = Debug File System launchConfigurationType.name.0 = Cancelling Launch Type launchConfigurationType.name.1 = Throwing Launch Type +launchConfigurationType.name.2 = Spy Launch Type testBreakpoint.name = Test Breakpoint \ No newline at end of file diff --git a/debug/org.eclipse.debug.tests/plugin.xml b/debug/org.eclipse.debug.tests/plugin.xml index 3738652a0cb..7f04486211b 100644 --- a/debug/org.eclipse.debug.tests/plugin.xml +++ b/debug/org.eclipse.debug.tests/plugin.xml @@ -35,25 +35,29 @@ - + - + - + - + @@ -77,7 +81,20 @@ modes="run" name="%launchConfigurationType.name.1"> + + + + + + + diff --git a/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java index 5e5e9ba65f6..82123effc57 100644 --- a/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java +++ b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java @@ -45,6 +45,7 @@ import org.eclipse.debug.tests.statushandlers.StatusHandlerTests; import org.eclipse.debug.tests.stepfilters.StepFiltersTests; import org.eclipse.debug.tests.ui.VariableValueEditorManagerTests; +import org.eclipse.debug.tests.ui.launchconfigurations.LaunchConfigurationTabGroupViewerTest; import org.eclipse.debug.tests.view.memory.MemoryRenderingTests; import org.eclipse.debug.tests.view.memory.TableRenderingTests; import org.eclipse.debug.tests.viewer.model.ChildrenUpdateTests; @@ -131,9 +132,11 @@ // Launch Groups LaunchGroupTests.class, + LaunchConfigurationTabGroupViewerTest.class, // Logical structure LogicalStructureCacheTest.class, + }) public class AutomatedSuite { } diff --git a/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/LaunchConfigurationTabGroupViewerTest.java b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/LaunchConfigurationTabGroupViewerTest.java new file mode 100644 index 00000000000..bf8bd78ce5f --- /dev/null +++ b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/LaunchConfigurationTabGroupViewerTest.java @@ -0,0 +1,158 @@ +package org.eclipse.debug.tests.ui.launchconfigurations; + +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunchConfigurationType; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.internal.ui.DebugUIPlugin; +import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationPresentationManager; +import org.eclipse.debug.internal.ui.launchConfigurations.LaunchConfigurationsDialog; +import org.eclipse.debug.tests.AbstractDebugTest; +import org.eclipse.debug.tests.ui.launchconfigurations.tabs.SpyTab; +import org.eclipse.debug.ui.IDebugUIConstants; +import org.eclipse.debug.ui.ILaunchConfigurationDialog; +import org.eclipse.debug.ui.ILaunchConfigurationTab; +import org.eclipse.debug.ui.ILaunchConfigurationTabGroup; +import org.eclipse.swt.widgets.Display; +import org.junit.Before; +import org.junit.Test; + +public class LaunchConfigurationTabGroupViewerTest extends AbstractDebugTest { + + private static interface ThrowingRunnable { + void run() throws T; + } + + private static final String LAUNCH_CONFIG_TYPE_ID = "spy.type"; + private static final String LAUNCH_CONFIG_MODE = ILaunchManager.RUN_MODE; + private ILaunchConfigurationType fLaunchConfigurationType; + private LaunchConfigurationsDialog fLaunchConfigurationsDialog; + + @Before + public void createDialog() throws CoreException { + fLaunchConfigurationType = getLaunchManager().getLaunchConfigurationType(LAUNCH_CONFIG_TYPE_ID); + ILaunchConfigurationTabGroup tabGroup = getLaunchConfigurationTabGroup(fLaunchConfigurationType); + + fLaunchConfigurationsDialog = (LaunchConfigurationsDialog) createLaunchConfigurationDialog(); + tabGroup.createTabs(fLaunchConfigurationsDialog, ILaunchManager.RUN_MODE); + } + + @Test + public void tesAllTabsAreInitializedByDefault() { + // Create a launch configuration with a unique name + ThrowingRunnable createAndSelect1LaunchConfig = () -> { + fLaunchConfigurationsDialog.getTabViewer().setInput(createLaunchConfigurationInstance()); + }; + + final ILaunchConfigurationTab[] tabs = runOnDialog(createAndSelect1LaunchConfig); + for (int i = 0; i < tabs.length; i++) { + assertThat("Tab " + i + " was not initialized", ((SpyTab) tabs[i]).isInitialized()); + } + } + + @Test + public void testFirstTabIsActivatedByDefault() { + // Create a launch configuration with a unique name + ThrowingRunnable createAndSelect1LaunchConfig = () -> { + fLaunchConfigurationsDialog.getTabViewer().setInput(createLaunchConfigurationInstance()); + }; + + final ILaunchConfigurationTab[] tabs = runOnDialog(createAndSelect1LaunchConfig); + assertThat("The 1st tab was not activated", ((SpyTab) tabs[0]).isActivated()); + } + + @Test + public void testOtherTabInOtherConfigIsActivated() { + int secondTabIndex = 1; + + ThrowingRunnable setActiveTab = () -> { + // Create and select launch config + fLaunchConfigurationsDialog.getTabViewer().setInput(createLaunchConfigurationInstance()); + + // Select another tab + fLaunchConfigurationsDialog.getTabViewer().setActiveTab(secondTabIndex); + + // Create a new launch config. This one should activate the same tab + // by default. + fLaunchConfigurationsDialog.getTabViewer().setInput(createLaunchConfigurationInstance()); + }; + + final ILaunchConfigurationTab[] tabs = runOnDialog(setActiveTab); + + assertThat("The 1st tab of the other launch configuration shouldn't have been activated", not(((SpyTab) tabs[0]).isActivated())); + assertThat("The tab was not activated", ((SpyTab) tabs[secondTabIndex]).isActivated()); + } + + @Test + public void testOtherTabIsActivated() { + int secondTabIndex = 1; + + ThrowingRunnable setActiveTab = () -> { + // Create and select launch config + fLaunchConfigurationsDialog.getTabViewer().setInput(createLaunchConfigurationInstance()); + + // Select another tab + fLaunchConfigurationsDialog.getTabViewer().setActiveTab(secondTabIndex); + }; + + final ILaunchConfigurationTab[] tabs = runOnDialog(setActiveTab); + + assertThat("The tab was not activated", ((SpyTab) tabs[secondTabIndex]).isActivated()); + } + + private ILaunchConfigurationWorkingCopy createLaunchConfigurationInstance() throws CoreException { + return fLaunchConfigurationType.newInstance(null, "MyLaunchConfiguration_" + System.currentTimeMillis()); + } + + private ILaunchConfigurationTab[] runOnDialog(ThrowingRunnable runnable) { + AtomicReference tabsRef = new AtomicReference<>(); + AtomicReference throwableRef = new AtomicReference<>(); + + Display.getCurrent().asyncExec(() -> { + try { + + runnable.run(); + + // I need to store the tabs here because the tab viewer (and all + // its tabs) are + // gone as soon as the dialog is closed + tabsRef.set(fLaunchConfigurationsDialog.getTabs()); + + } catch (Throwable e) { + // neither calling "fail" not throwing an exception will let the + // test fail so I + // need to store this and check it outside of the runnable + throwableRef.set(e); + DebugPlugin.log(e); + } finally { + fLaunchConfigurationsDialog.close(); + } + }); + + fLaunchConfigurationsDialog.open(); + + if (throwableRef.get() != null) { + throw new AssertionError("An exception occurred while executing the runnable.", throwableRef.get()); + } + + return tabsRef.get(); + } + + protected ILaunchConfigurationTabGroup getLaunchConfigurationTabGroup(ILaunchConfigurationType launchConfigurationType) throws CoreException { + return LaunchConfigurationPresentationManager.getDefault().getTabGroup(launchConfigurationType, LAUNCH_CONFIG_MODE); + } + + protected ILaunchConfigurationDialog createLaunchConfigurationDialog() { + return new LaunchConfigurationsDialog(null, DebugUIPlugin.getDefault().getLaunchConfigurationManager().getLaunchGroup(IDebugUIConstants.ID_DEBUG_LAUNCH_GROUP)); + } + + protected ILaunchManager getLaunchManager() { + return DebugPlugin.getDefault().getLaunchManager(); + } +} diff --git a/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/tabs/SpyTab.java b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/tabs/SpyTab.java new file mode 100644 index 00000000000..a2d2edbaf10 --- /dev/null +++ b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/tabs/SpyTab.java @@ -0,0 +1,62 @@ +package org.eclipse.debug.tests.ui.launchconfigurations.tabs; + +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.swt.widgets.Composite; + +/** + * A Tab whose sole purpose is to say if it was initialized and activated + * properly + */ +public abstract class SpyTab extends AbstractLaunchConfigurationTab { + + private boolean initialized; + private boolean activated; + + @Override + public void createControl(Composite parent) { + } + + @Override + public String getName() { + return getClass().getSimpleName(); + } + + @Override + public void initializeFrom(ILaunchConfiguration configuration) { + initialized = true; + } + + @Override + public void activated(ILaunchConfigurationWorkingCopy workingCopy) { + activated = true; + } + + @Override + public void performApply(ILaunchConfigurationWorkingCopy configuration) { + } + + @Override + public void setDefaults(ILaunchConfigurationWorkingCopy configuration) { + } + + public boolean isInitialized() { + return initialized; + } + + public boolean isActivated() { + return activated; + } + + // These 3 are necessary because I need 3 tabs in the launch config and using + // always the same kind of tab produces incorrect results + public static class SpyTabA extends SpyTab { + } + + public static class SpyTabB extends SpyTab { + } + + public static class SpyTabC extends SpyTab { + } +} diff --git a/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/tabs/SpyTabGroup.java b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/tabs/SpyTabGroup.java new file mode 100644 index 00000000000..a04c1983f15 --- /dev/null +++ b/debug/org.eclipse.debug.tests/src/org/eclipse/debug/tests/ui/launchconfigurations/tabs/SpyTabGroup.java @@ -0,0 +1,17 @@ +package org.eclipse.debug.tests.ui.launchconfigurations.tabs; + +import org.eclipse.debug.tests.ui.launchconfigurations.tabs.SpyTab.SpyTabA; +import org.eclipse.debug.tests.ui.launchconfigurations.tabs.SpyTab.SpyTabB; +import org.eclipse.debug.tests.ui.launchconfigurations.tabs.SpyTab.SpyTabC; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup; +import org.eclipse.debug.ui.ILaunchConfigurationDialog; +import org.eclipse.debug.ui.ILaunchConfigurationTab; + +public class SpyTabGroup extends AbstractLaunchConfigurationTabGroup { + + @Override + public void createTabs(ILaunchConfigurationDialog dialog, String mode) { + setTabs(new ILaunchConfigurationTab[] { new SpyTabA(), new SpyTabB(), new SpyTabC() }); + } + +} \ No newline at end of file diff --git a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationTabGroupViewer.java b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationTabGroupViewer.java index 2ba0dd7e72c..c3f8c32f4cc 100644 --- a/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationTabGroupViewer.java +++ b/debug/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/launchConfigurations/LaunchConfigurationTabGroupViewer.java @@ -22,6 +22,7 @@ import java.text.MessageFormat; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import org.eclipse.core.resources.IFile; @@ -722,7 +723,9 @@ protected void inputChanged(Object input) { if (finput instanceof ILaunchConfiguration configuration) { boolean refreshTabs = true; if (fWorkingCopy != null - && fWorkingCopy.getOriginal().equals(configuration.getWorkingCopy().getOriginal())) { + && fWorkingCopy.getOriginal() != null // + && Objects.equals(fWorkingCopy.getOriginal(), + configuration.getWorkingCopy().getOriginal())) { refreshTabs = false; } fOriginal = configuration; @@ -1449,19 +1452,39 @@ protected void handleTabSelected() { if (fDisposingTabs || fInitializingTabs) { return; } + int oldCurrentTabIndex = fCurrentTabIndex; + fCurrentTabIndex = fTabFolder.getSelectionIndex(); + ILaunchConfigurationTab[] tabs = getTabs(); - if (fCurrentTabIndex == fTabFolder.getSelectionIndex() || tabs == null || tabs.length == 0 || fCurrentTabIndex > (tabs.length - 1)) { + if (oldCurrentTabIndex == fCurrentTabIndex || tabs == null || tabs.length == 0 + || oldCurrentTabIndex > (tabs.length - 1)) { return; } - if (fCurrentTabIndex != -1) { - ILaunchConfigurationTab tab = tabs[fCurrentTabIndex]; - ILaunchConfigurationWorkingCopy wc = getWorkingCopy(); - if (wc != null) { - tab.deactivated(wc); - getActiveTab().activated(wc); - } + + deactivateTab(oldCurrentTabIndex); + + activateCurrentlyActiveTab(); + } + + private void deactivateTab(int tabIndex) { + ILaunchConfigurationWorkingCopy wc = getWorkingCopy(); + + if (tabIndex < 0 || wc == null) { + return; } - fCurrentTabIndex = fTabFolder.getSelectionIndex(); + + getTabs()[tabIndex].deactivated(wc); + } + + private void activateCurrentlyActiveTab() { + ILaunchConfigurationWorkingCopy wc = getWorkingCopy(); + ILaunchConfigurationTab activeTab = getActiveTab(); + + if (wc == null || activeTab == null) { + return; + } + + activeTab.activated(wc); } /**