Skip to content

Commit e680a7d

Browse files
committed
Check for mixed JUnit 5 and JUnit 6 launch type and required bundles
This changes ensures an error dialog is shown, if a user runs a JUnit 5 launch with required JUnit 6 bundles. Fixes: #2045
1 parent dd6dca3 commit e680a7d

File tree

5 files changed

+133
-0
lines changed

5 files changed

+133
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Simeon Andreev and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Simeon Andreev - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.pde.internal.launching;
15+
16+
import java.util.Arrays;
17+
import java.util.HashMap;
18+
import java.util.HashSet;
19+
import java.util.LinkedHashMap;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Set;
23+
import java.util.stream.Collectors;
24+
25+
import org.eclipse.core.runtime.CoreException;
26+
import org.eclipse.core.runtime.IProgressMonitor;
27+
import org.eclipse.core.runtime.IStatus;
28+
import org.eclipse.core.runtime.Status;
29+
import org.eclipse.debug.core.DebugPlugin;
30+
import org.eclipse.debug.core.ILaunchConfiguration;
31+
import org.eclipse.debug.core.IStatusHandler;
32+
import org.eclipse.osgi.service.resolver.BundleDescription;
33+
import org.eclipse.osgi.util.NLS;
34+
import org.eclipse.pde.core.plugin.IPluginModelBase;
35+
import org.eclipse.pde.internal.launching.launcher.LaunchValidationOperation;
36+
37+
public class JUnitLaunchValidationOperation extends LaunchValidationOperation {
38+
39+
private static final Set<String> JUNIT_JUPITER_BUNLDES = new HashSet<>(Arrays.asList(new String[] {
40+
"junit-jupiter-api", //$NON-NLS-1$
41+
"org.junit.jupiter.api", //$NON-NLS-1$
42+
"junit-jupiter-engine", //$NON-NLS-1$
43+
"org.junit.jupiter.engine", //$NON-NLS-1$
44+
}));
45+
46+
private static final Object[] EMPTY = new Object[0];
47+
private final Map<Object, Object[]> fErrors = new HashMap<>(2);
48+
49+
public JUnitLaunchValidationOperation(ILaunchConfiguration configuration, Set<IPluginModelBase> models) {
50+
super(configuration, models, null);
51+
}
52+
53+
@Override
54+
public void run(IProgressMonitor monitor) throws CoreException {
55+
try {
56+
checkJunitVersion(fLaunchConfiguration, fModels);
57+
} catch (CoreException e) {
58+
PDELaunchingPlugin.log(e);
59+
}
60+
}
61+
62+
@SuppressWarnings("restriction")
63+
private void checkJunitVersion(ILaunchConfiguration configuration, Set<IPluginModelBase> models) throws CoreException {
64+
org.eclipse.jdt.internal.junit.launcher.ITestKind testKind = org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration);
65+
if (testKind.isNull()) {
66+
return;
67+
}
68+
String testKindId = testKind.getId();
69+
boolean junit5Launch = org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKindId);
70+
if (junit5Launch) {
71+
List<BundleDescription> junitBundles = junitBundles(models);
72+
List<BundleDescription> junit5Bundles = junitBundles.stream().filter(d -> d.getVersion().getMajor() <= 5).toList();
73+
List<BundleDescription> junit6Bundles = junitBundles.stream().filter(d -> d.getVersion().getMajor() == 6).toList();
74+
75+
if (!junit5Bundles.isEmpty() && !junit6Bundles.isEmpty()) {
76+
String junit5BundleIds = toString(junit5Bundles);
77+
String junit6BundleIds = toString(junit6Bundles);
78+
String message = NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_MixedJUnit5And6Runtime, junit5BundleIds, junit6BundleIds);
79+
addError(message);
80+
}
81+
if (!junit6Bundles.isEmpty() && junit5Launch) {
82+
String junit6BundleIds = toString(junit6Bundles);
83+
String message = NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_JUnit5LaunchJUnit6Runtime, junit6BundleIds);
84+
addError(message);
85+
}
86+
}
87+
}
88+
89+
private void addError(String message) throws CoreException {
90+
IStatus status = Status.error(message);
91+
IStatusHandler statusHandler = DebugPlugin.getDefault().getStatusHandler(status);
92+
Object extensionError = null;
93+
if (statusHandler == null) {
94+
extensionError = status.getMessage();
95+
} else {
96+
extensionError = statusHandler.handleStatus(status, message);
97+
}
98+
fErrors.put(extensionError, EMPTY);
99+
}
100+
101+
@Override
102+
public boolean hasErrors() {
103+
return !fErrors.isEmpty();
104+
}
105+
106+
@Override
107+
public Map<Object, Object[]> getInput() {
108+
Map<Object, Object[]> map = new LinkedHashMap<>();
109+
map.putAll(fErrors);
110+
return map;
111+
}
112+
113+
private static List<BundleDescription> junitBundles(Set<IPluginModelBase> models) {
114+
return models.stream().map(IPluginModelBase::getBundleDescription).filter(d -> JUNIT_JUPITER_BUNLDES.contains(d.getSymbolicName())).toList();
115+
}
116+
117+
private static String toString(List<BundleDescription> bundleDescriptions) {
118+
return bundleDescriptions.stream().map(BundleDescription::getSymbolicName).collect(Collectors.joining(System.lineSeparator()));
119+
}
120+
121+
}

ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/PDEMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ public class PDEMessages extends NLS {
3636
public static String WorkbenchLauncherConfigurationDelegate_noStartup;
3737
public static String JUnitLaunchConfiguration_error_notaplugin;
3838
public static String JUnitLaunchConfiguration_error_missingPlugin;
39+
public static String JUnitLaunchConfiguration_error_MixedJUnit5And6Runtime;
40+
public static String JUnitLaunchConfiguration_error_JUnit5LaunchJUnit6Runtime;
3941

4042
public static String OSGiLaunchConfiguration_cannotFindLaunchConfiguration;
4143
public static String OSGiLaunchConfiguration_selected;

ui/org.eclipse.pde.launching/src/org/eclipse/pde/internal/launching/pderesources.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ WorkbenchLauncherConfigurationDelegate_jrePathNotFound = The installation path t
2525
WorkbenchLauncherConfigurationDelegate_noStartup = Launching failed. Bootstrap code cannot be found.
2626
JUnitLaunchConfiguration_error_notaplugin = Could not launch the JUnit plug-in tests because project ''{0}'' is not a plug-in project.
2727
JUnitLaunchConfiguration_error_missingPlugin = Required plug-in ''{0}'' could not be found.
28+
JUnitLaunchConfiguration_error_MixedJUnit5And6Runtime = Plug-in requires both JUnit 5 and JUnit 6 bundles.\nUpdate the plug-in to require either JUnit 5 or JUnit 6.\nJUnit 5 bundles:\n{0}\nJUnit 6 bundles:\n{0}
29+
JUnitLaunchConfiguration_error_JUnit5LaunchJUnit6Runtime = JUnit 5 type launch cannot run with JUnit 6 bundles.\nUpdate the launch to use JUnit 6,\nor restrict version requirements of the following bundles to JUnit 5:\n{0}
2830

2931
OSGiLaunchConfiguration_cannotFindLaunchConfiguration=Cannot find the {0} OSGi framework.
3032
OSGiLaunchConfiguration_selected=selected

ui/org.eclipse.pde.launching/src/org/eclipse/pde/launching/JUnitLaunchConfigurationDelegate.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import org.eclipse.pde.internal.core.util.VersionUtil;
7272
import org.eclipse.pde.internal.launching.IPDEConstants;
7373
import org.eclipse.pde.internal.launching.JUnitLaunchRequirements;
74+
import org.eclipse.pde.internal.launching.JUnitLaunchValidationOperation;
7475
import org.eclipse.pde.internal.launching.PDELaunchingPlugin;
7576
import org.eclipse.pde.internal.launching.PDEMessages;
7677
import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
@@ -518,6 +519,9 @@ protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch
518519
fAllBundles = fModels.keySet().stream().collect(Collectors.groupingBy(m -> m.getPluginBase().getId(), LinkedHashMap::new, Collectors.toCollection(ArrayList::new)));
519520
launchMode = launch.getLaunchMode();
520521

522+
JUnitLaunchValidationOperation junitValidation = new JUnitLaunchValidationOperation(configuration, fModels.keySet());
523+
LaunchPluginValidator.runValidationOperation(junitValidation, monitor);
524+
521525
// implicitly add the plug-ins required for JUnit testing if necessary
522526
JUnitLaunchRequirements.addRequiredJunitRuntimePlugins(configuration, fAllBundles, fModels);
523527

ui/org.eclipse.pde.unittest.junit/src/org/eclipse/pde/unittest/junit/launcher/JUnitPluginLaunchConfigurationDelegate.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
import org.eclipse.pde.internal.core.util.CoreUtility;
8787
import org.eclipse.pde.internal.launching.IPDEConstants;
8888
import org.eclipse.pde.internal.launching.JUnitLaunchRequirements;
89+
import org.eclipse.pde.internal.launching.JUnitLaunchValidationOperation;
8990
import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper;
9091
import org.eclipse.pde.internal.launching.launcher.EclipsePluginValidationOperation;
9192
import org.eclipse.pde.internal.launching.launcher.LaunchArgumentsHelper;
@@ -359,6 +360,9 @@ protected void preLaunchCheck(ILaunchConfiguration configuration, ILaunch launch
359360
fAllBundles = fModels.keySet().stream().collect(Collectors.groupingBy(m -> m.getPluginBase().getId(),
360361
LinkedHashMap::new, Collectors.toCollection(ArrayList::new)));
361362

363+
JUnitLaunchValidationOperation junitValidation = new JUnitLaunchValidationOperation(configuration, fModels.keySet());
364+
LaunchPluginValidator.runValidationOperation(junitValidation, monitor);
365+
362366
// implicitly add the plug-ins required for JUnit testing if necessary
363367
JUnitLaunchRequirements.addRequiredJunitRuntimePlugins(configuration, fAllBundles, fModels);
364368

0 commit comments

Comments
 (0)