From 9050251e9983021ee54c601c99858865aa93a582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Thu, 23 Oct 2025 10:52:36 +0200 Subject: [PATCH] Centralize code used in two places to compute JUnit requirements Currently we have almost identical code in JUnitLaunchConfigurationDelegate and JUnitPluginLaunchConfigurationDelegate to compute the JUnit requirements. This now extract the code into a central place JUnitLaunchRequirements for consistency and maintenance. Co-authored-by: Simeon Andreev --- .../forceQualifierUpdate.txt | 3 +- .../launching/JUnitLaunchRequirements.java | 102 ++++++++++++++++++ .../JUnitLaunchConfigurationDelegate.java | 74 +------------ ui/org.eclipse.pde.ui/.settings/.api_filters | 9 -- .../pde/internal/ui/launcher/PluginBlock.java | 5 +- .../.settings/.api_filters | 9 -- ...UnitPluginLaunchConfigurationDelegate.java | 58 +--------- 7 files changed, 111 insertions(+), 149 deletions(-) create mode 100644 ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/JUnitLaunchRequirements.java diff --git a/org.eclipse.pde.doc.user/forceQualifierUpdate.txt b/org.eclipse.pde.doc.user/forceQualifierUpdate.txt index c27f50cc8fe..274d2fed670 100644 --- a/org.eclipse.pde.doc.user/forceQualifierUpdate.txt +++ b/org.eclipse.pde.doc.user/forceQualifierUpdate.txt @@ -1 +1,2 @@ -Javadoc generation options have changed for 4.38 \ No newline at end of file +Javadoc generation options have changed for 4.38 +Removed non reference method from public API class \ No newline at end of file diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/JUnitLaunchRequirements.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/JUnitLaunchRequirements.java new file mode 100644 index 00000000000..e70ddd05bea --- /dev/null +++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/JUnitLaunchRequirements.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2006, 2025 IBM Corporation and others. + * + * 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.pde.internal.launching; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.osgi.service.resolver.BundleDescription; +import org.eclipse.osgi.util.NLS; +import org.eclipse.pde.core.plugin.IPluginModelBase; +import org.eclipse.pde.core.plugin.PluginRegistry; +import org.eclipse.pde.internal.core.DependencyManager; +import org.eclipse.pde.internal.core.PDECore; +import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper; + +public class JUnitLaunchRequirements { + + public static final String JUNIT4_JDT_RUNTIME_PLUGIN = "org.eclipse.jdt.junit4.runtime"; //$NON-NLS-1$ + public static final String JUNIT5_JDT_RUNTIME_PLUGIN = "org.eclipse.jdt.junit5.runtime"; //$NON-NLS-1$ + + public static void addRequiredJunitRuntimePlugins(ILaunchConfiguration configuration, Map> allBundles, Map allModels) throws CoreException { + Set requiredPlugins = new LinkedHashSet<>(getRequiredJunitRuntimeEclipsePlugins(configuration)); + + if (allBundles.containsKey("junit-platform-runner")) { //$NON-NLS-1$ + // add launcher and jupiter.engine to support @RunWith(JUnitPlatform.class) + requiredPlugins.add("junit-platform-launcher"); //$NON-NLS-1$ + requiredPlugins.add("junit-jupiter-engine"); //$NON-NLS-1$ + } + + Set addedRequirements = new HashSet<>(); + addAbsentRequirements(requiredPlugins, addedRequirements, allBundles, allModels); + + Set requirementsOfRequirements = DependencyManager.findRequirementsClosure(addedRequirements); + Set rorIds = requirementsOfRequirements.stream().map(BundleDescription::getSymbolicName).collect(Collectors.toSet()); + addAbsentRequirements(rorIds, null, allBundles, allModels); + } + + @SuppressWarnings("restriction") + public static Collection getRequiredJunitRuntimeEclipsePlugins(ILaunchConfiguration configuration) { + org.eclipse.jdt.internal.junit.launcher.ITestKind testKind = org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration); + if (testKind.isNull()) { + return Collections.emptyList(); + } + List plugins = new ArrayList<>(); + plugins.add("org.eclipse.pde.junit.runtime"); //$NON-NLS-1$ + + if (org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId())) { + plugins.add("org.eclipse.jdt.junit4.runtime"); //$NON-NLS-1$ + } else if (org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKind.getId())) { + plugins.add("org.eclipse.jdt.junit5.runtime"); //$NON-NLS-1$ + } + return plugins; + } + + private static void addAbsentRequirements(Collection requirements, Set addedRequirements, Map> allBundles, Map allModels) throws CoreException { + for (String id : requirements) { + List models = allBundles.computeIfAbsent(id, k -> new ArrayList<>()); + if (models.stream().noneMatch(m -> m.getBundleDescription().isResolved())) { + IPluginModelBase model = findRequiredPluginInTargetOrHost(id); + models.add(model); + BundleLauncherHelper.addDefaultStartingBundle(allModels, model); + if (addedRequirements != null) { + addedRequirements.add(model.getBundleDescription()); + } + } + } + } + + private static IPluginModelBase findRequiredPluginInTargetOrHost(String id) throws CoreException { + IPluginModelBase model = PluginRegistry.findModel(id); + if (model == null || !model.getBundleDescription().isResolved()) { + // prefer bundle from host over unresolved bundle from target + model = PDECore.getDefault().findPluginInHost(id).max(Comparator.comparing(p -> p.getBundleDescription().getVersion())).orElse(null); + } + if (model == null) { + throw new CoreException(Status.error(NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_missingPlugin, id))); + } + return model; + } +} diff --git a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java index 4304df49da5..dfd2610cdf1 100644 --- a/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java +++ b/ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java @@ -24,16 +24,12 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; -import java.util.Set; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.stream.Collectors; @@ -58,7 +54,6 @@ import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.IVMRunner; import org.eclipse.jdt.launching.JavaRuntime; -import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.util.ManifestElement; import org.eclipse.osgi.util.NLS; import org.eclipse.pde.core.plugin.IFragment; @@ -69,14 +64,13 @@ import org.eclipse.pde.core.plugin.TargetPlatform; import org.eclipse.pde.internal.build.IPDEBuildConstants; import org.eclipse.pde.internal.core.ClasspathHelper; -import org.eclipse.pde.internal.core.DependencyManager; import org.eclipse.pde.internal.core.ICoreConstants; -import org.eclipse.pde.internal.core.PDECore; import org.eclipse.pde.internal.core.TargetPlatformHelper; import org.eclipse.pde.internal.core.bnd.PdeProjectAnalyzer; import org.eclipse.pde.internal.core.util.CoreUtility; import org.eclipse.pde.internal.core.util.VersionUtil; import org.eclipse.pde.internal.launching.IPDEConstants; +import org.eclipse.pde.internal.launching.JUnitLaunchRequirements; import org.eclipse.pde.internal.launching.PDELaunchingPlugin; import org.eclipse.pde.internal.launching.PDEMessages; import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper; @@ -393,18 +387,6 @@ protected String getApplication(ILaunchConfiguration configuration) { return application; } - private IPluginModelBase findRequiredPluginInTargetOrHost(String id) throws CoreException { - IPluginModelBase model = PluginRegistry.findModel(id); - if (model == null || !model.getBundleDescription().isResolved()) { - // prefer bundle from host over unresolved bundle from target - model = PDECore.getDefault().findPluginInHost(id).max(Comparator.comparing(p -> p.getBundleDescription().getVersion())).orElse(null); - } - if (model == null) { - abort(NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_missingPlugin, id), null, IStatus.OK); - } - return model; - } - @Override public String getProgramArguments(ILaunchConfiguration configuration) throws CoreException { return LaunchArgumentsHelper.getUserProgramArguments(configuration); @@ -537,7 +519,7 @@ protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch launchMode = launch.getLaunchMode(); // implicitly add the plug-ins required for JUnit testing if necessary - addRequiredJunitRuntimePlugins(configuration); + JUnitLaunchRequirements.addRequiredJunitRuntimePlugins(configuration, fAllBundles, fModels); String attribute = launch.getAttribute(PDE_JUNIT_SHOW_COMMAND); boolean isShowCommand = false; @@ -558,58 +540,6 @@ protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch synchronizeManifests(configuration, subMonitor.split(1)); } - private void addRequiredJunitRuntimePlugins(ILaunchConfiguration configuration) throws CoreException { - Set requiredPlugins = new LinkedHashSet<>(getRequiredJunitRuntimePlugins(configuration)); - - if (fAllBundles.containsKey("junit-platform-runner") || fAllBundles.containsKey("org.junit.platform.runner")) { //$NON-NLS-1$ //$NON-NLS-2$ - // add launcher and jupiter.engine to support @RunWith(JUnitPlatform.class) - requiredPlugins.add("junit-platform-launcher"); //$NON-NLS-1$ - requiredPlugins.add("junit-jupiter-engine"); //$NON-NLS-1$ - } - Set addedRequirements = new HashSet<>(); - addAbsentRequirements(requiredPlugins, addedRequirements); - - Set requirementsOfRequirements = DependencyManager.findRequirementsClosure(addedRequirements); - Set rorIds = requirementsOfRequirements.stream().map(BundleDescription::getSymbolicName).collect(Collectors.toSet()); - addAbsentRequirements(rorIds, null); - } - - private void addAbsentRequirements(Collection requirements, Set addedRequirements) throws CoreException { - for (String id : requirements) { - List models = fAllBundles.computeIfAbsent(id, k -> new ArrayList<>()); - if (models.stream().noneMatch(m -> m.getBundleDescription().isResolved())) { - IPluginModelBase model = findRequiredPluginInTargetOrHost(id); - models.add(model); - BundleLauncherHelper.addDefaultStartingBundle(fModels, model); - if (addedRequirements != null) { - addedRequirements.add(model.getBundleDescription()); - } - } - } - } - - /** - * @noreference This method is not intended to be referenced by clients. - * @param configuration non null config - * @return required plugins - */ - @SuppressWarnings("restriction") - public static Collection getRequiredJunitRuntimePlugins(ILaunchConfiguration configuration) { - org.eclipse.jdt.internal.junit.launcher.ITestKind testKind = org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration); - if (testKind.isNull()) { - return Collections.emptyList(); - } - List plugins = new ArrayList<>(); - plugins.add("org.eclipse.pde.junit.runtime"); //$NON-NLS-1$ - - if (org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId())) { - plugins.add("org.eclipse.jdt.junit4.runtime"); //$NON-NLS-1$ - } else if (org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKind.getId())) { - plugins.add("org.eclipse.jdt.junit5.runtime"); //$NON-NLS-1$ - } - return plugins; - } - /** * Checks for old-style plugin.xml files that have become stale since the last launch. * For any stale plugin.xml files found, the corresponding MANIFEST.MF is deleted diff --git a/ui/org.eclipse.pde.ui/.settings/.api_filters b/ui/org.eclipse.pde.ui/.settings/.api_filters index c0125668ef8..bb8bb419723 100644 --- a/ui/org.eclipse.pde.ui/.settings/.api_filters +++ b/ui/org.eclipse.pde.ui/.settings/.api_filters @@ -95,15 +95,6 @@ - - - - - - - - - diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/PluginBlock.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/PluginBlock.java index 2a62284062a..ec4a0810a21 100644 --- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/PluginBlock.java +++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/launcher/PluginBlock.java @@ -27,13 +27,13 @@ import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.pde.core.plugin.IPluginModelBase; import org.eclipse.pde.core.plugin.PluginRegistry; +import org.eclipse.pde.internal.launching.JUnitLaunchRequirements; import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper; import org.eclipse.pde.internal.launching.launcher.EclipsePluginValidationOperation; import org.eclipse.pde.internal.launching.launcher.LaunchValidationOperation; import org.eclipse.pde.internal.launching.launcher.RequirementHelper; import org.eclipse.pde.internal.ui.PDEPlugin; import org.eclipse.pde.launching.IPDELauncherConstants; -import org.eclipse.pde.launching.JUnitLaunchConfigurationDelegate; import org.eclipse.pde.ui.launcher.AbstractLauncherTab; public class PluginBlock extends AbstractPluginBlock { @@ -165,7 +165,8 @@ protected void addRequiredPlugins() { // Check that the application or product we are launching has its requirements included try { List requiredIds = RequirementHelper.getApplicationLaunchRequirements(fLaunchConfig); - Collection requiredPlugins = JUnitLaunchConfigurationDelegate.getRequiredJunitRuntimePlugins(fLaunchConfig); + Collection requiredPlugins = JUnitLaunchRequirements + .getRequiredJunitRuntimeEclipsePlugins(fLaunchConfig); Stream.concat(requiredPlugins.stream(), requiredIds.stream()).forEach(requiredId -> { // see if launcher plugin is already included IPluginModelBase base = findPlugin(requiredId); diff --git a/ui/org.eclipse.pde.unittest.junit/.settings/.api_filters b/ui/org.eclipse.pde.unittest.junit/.settings/.api_filters index bdc52b17156..b0d16a484dc 100644 --- a/ui/org.eclipse.pde.unittest.junit/.settings/.api_filters +++ b/ui/org.eclipse.pde.unittest.junit/.settings/.api_filters @@ -8,15 +8,6 @@ - - - - - - - - - diff --git a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchConfigurationDelegate.java b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchConfigurationDelegate.java index 40e608e0856..b7569339830 100644 --- a/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchConfigurationDelegate.java +++ b/ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchConfigurationDelegate.java @@ -26,11 +26,8 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; import java.util.HashSet; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -78,19 +75,17 @@ import org.eclipse.jdt.launching.VMRunnerConfiguration; import org.eclipse.jdt.ui.unittest.junit.JUnitTestPlugin; import org.eclipse.jdt.ui.unittest.junit.JUnitTestPlugin.JUnitVersion; -import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.util.NLS; import org.eclipse.pde.core.plugin.IFragmentModel; import org.eclipse.pde.core.plugin.IPluginModelBase; import org.eclipse.pde.core.plugin.PluginRegistry; import org.eclipse.pde.core.plugin.TargetPlatform; import org.eclipse.pde.internal.core.ClasspathHelper; -import org.eclipse.pde.internal.core.DependencyManager; import org.eclipse.pde.internal.core.ICoreConstants; -import org.eclipse.pde.internal.core.PDECore; import org.eclipse.pde.internal.core.TargetPlatformHelper; import org.eclipse.pde.internal.core.util.CoreUtility; import org.eclipse.pde.internal.launching.IPDEConstants; +import org.eclipse.pde.internal.launching.JUnitLaunchRequirements; import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper; import org.eclipse.pde.internal.launching.launcher.EclipsePluginValidationOperation; import org.eclipse.pde.internal.launching.launcher.LaunchArgumentsHelper; @@ -100,7 +95,6 @@ import org.eclipse.pde.internal.launching.launcher.RequirementHelper; import org.eclipse.pde.internal.launching.launcher.VMHelper; import org.eclipse.pde.launching.IPDELauncherConstants; -import org.eclipse.pde.launching.JUnitLaunchConfigurationDelegate; import org.eclipse.pde.launching.PDESourcePathProvider; import org.eclipse.pde.unittest.junit.JUnitPluginTestPlugin; import org.osgi.framework.Bundle; @@ -366,7 +360,7 @@ protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch LinkedHashMap::new, Collectors.toCollection(ArrayList::new))); // implicitly add the plug-ins required for JUnit testing if necessary - addRequiredJunitRuntimePlugins(configuration); + JUnitLaunchRequirements.addRequiredJunitRuntimePlugins(configuration, fAllBundles, fModels); String attribute = launch.getAttribute(PDE_JUNIT_SHOW_COMMAND); boolean isShowCommand = false; @@ -387,41 +381,6 @@ protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch synchronizeManifests(configuration, subMonitor.split(1)); } - private void addRequiredJunitRuntimePlugins(ILaunchConfiguration configuration) throws CoreException { - Set requiredPlugins = new LinkedHashSet<>( - JUnitLaunchConfigurationDelegate.getRequiredJunitRuntimePlugins(configuration)); - - if (fAllBundles.containsKey("junit-platform-runner")) { //$NON-NLS-1$ - // add launcher and jupiter.engine to support @RunWith(JUnitPlatform.class) - requiredPlugins.add("junit-platform-launcher"); //$NON-NLS-1$ - requiredPlugins.add("junit-jupiter-engine"); //$NON-NLS-1$ - } - - Set addedRequirements = new HashSet<>(); - addAbsentRequirements(requiredPlugins, addedRequirements); - - Set requirementsOfRequirements = DependencyManager - .findRequirementsClosure(addedRequirements); - Set rorIds = requirementsOfRequirements.stream().map(BundleDescription::getSymbolicName) - .collect(Collectors.toSet()); - addAbsentRequirements(rorIds, null); - } - - private void addAbsentRequirements(Collection requirements, Set addedRequirements) - throws CoreException { - for (String id : requirements) { - List models = fAllBundles.computeIfAbsent(id, k -> new ArrayList<>()); - if (models.stream().noneMatch(m -> m.getBundleDescription().isResolved())) { - IPluginModelBase model = findRequiredPluginInTargetOrHost(id); - models.add(model); - BundleLauncherHelper.addDefaultStartingBundle(fModels, model); - if (addedRequirements != null) { - addedRequirements.add(model.getBundleDescription()); - } - } - } - } - @Override public String getJavaProjectName(ILaunchConfiguration configuration) throws CoreException { return configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String) null); @@ -1086,19 +1045,6 @@ protected String getApplication(ILaunchConfiguration configuration) { return application; } - private IPluginModelBase findRequiredPluginInTargetOrHost(String id) throws CoreException { - IPluginModelBase model = PluginRegistry.findModel(id); - if (model == null || !model.getBundleDescription().isResolved()) { - // prefer bundle from host over unresolved bundle from target - model = PDECore.getDefault().findPluginInHost(id) - .max(Comparator.comparing(p -> p.getBundleDescription().getVersion())).orElse(null); - } - if (model == null) { - abort(NLS.bind(Messages.JUnitPluginLaunchConfigurationDelegate_error_missingPlugin, id), null, IStatus.OK); - } - return model; - } - @Override public String getProgramArguments(ILaunchConfiguration configuration) throws CoreException { return LaunchArgumentsHelper.getUserProgramArguments(configuration);