Skip to content

Commit 766de63

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 9cf237e commit 766de63

File tree

5 files changed

+114
-0
lines changed

5 files changed

+114
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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.HashMap;
17+
import java.util.LinkedHashMap;
18+
import java.util.Map;
19+
import java.util.Optional;
20+
import java.util.Set;
21+
import java.util.stream.Stream;
22+
23+
import org.eclipse.core.runtime.CoreException;
24+
import org.eclipse.core.runtime.IProgressMonitor;
25+
import org.eclipse.core.runtime.Status;
26+
import org.eclipse.debug.core.ILaunchConfiguration;
27+
import org.eclipse.osgi.service.resolver.BundleDescription;
28+
import org.eclipse.osgi.util.NLS;
29+
import org.eclipse.pde.core.plugin.IPluginModelBase;
30+
import org.eclipse.pde.internal.launching.launcher.LaunchValidationOperation;
31+
import org.osgi.framework.Version;
32+
33+
public class JUnitLaunchValidationOperation extends LaunchValidationOperation {
34+
35+
private static final Set<String> JUNIT_JUPITER_BUNLDES = Set.of(new String[] {
36+
"junit-jupiter-engine", //$NON-NLS-1$
37+
"org.junit.jupiter.engine", //$NON-NLS-1$
38+
});
39+
40+
private static final Object[] EMPTY = new Object[0];
41+
private final Map<Object, Object[]> fErrors = new HashMap<>(2);
42+
43+
public JUnitLaunchValidationOperation(ILaunchConfiguration configuration, Set<IPluginModelBase> models) {
44+
super(configuration, models, null);
45+
}
46+
47+
@Override
48+
public void run(IProgressMonitor monitor) throws CoreException {
49+
try {
50+
checkJunitVersion(fLaunchConfiguration, fModels);
51+
} catch (CoreException e) {
52+
PDELaunchingPlugin.log(e);
53+
}
54+
}
55+
56+
@SuppressWarnings("restriction")
57+
private void checkJunitVersion(ILaunchConfiguration configuration, Set<IPluginModelBase> models) throws CoreException {
58+
org.eclipse.jdt.internal.junit.launcher.ITestKind testKind = org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration);
59+
if (testKind.isNull()) {
60+
return;
61+
}
62+
Stream<Version> junitBundlesVersions = junitBundleVersions(models);
63+
String testKindId = testKind.getId();
64+
switch (testKindId) {
65+
case org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT3_TEST_KIND_ID,
66+
org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT4_TEST_KIND_ID -> {
67+
// nothing to check
68+
}
69+
case org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT5_TEST_KIND_ID -> {
70+
Optional<Integer> otherVersion = junitBundlesVersions.map(Version::getMajor).filter(i -> i.intValue() != 5).findFirst();
71+
if (otherVersion.isPresent()) {
72+
String message = NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch, 5, otherVersion.get());
73+
addError(message);
74+
}
75+
}
76+
default -> throw new CoreException(Status.error("Unsupported test kind: " + testKindId)); //$NON-NLS-1$
77+
}
78+
}
79+
80+
private void addError(String message) {
81+
fErrors.put(message, EMPTY);
82+
}
83+
84+
@Override
85+
public boolean hasErrors() {
86+
return !fErrors.isEmpty();
87+
}
88+
89+
@Override
90+
public Map<Object, Object[]> getInput() {
91+
Map<Object, Object[]> map = new LinkedHashMap<>();
92+
map.putAll(fErrors);
93+
return map;
94+
}
95+
96+
private static Stream<Version> junitBundleVersions(Set<IPluginModelBase> models) {
97+
return models.stream().map(IPluginModelBase::getBundleDescription).filter(d -> JUNIT_JUPITER_BUNLDES.contains(d.getSymbolicName())).map(BundleDescription::getVersion);
98+
}
99+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ 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_JUnitLaunchAndRuntimeMissmatch;
3940

4041
public static String OSGiLaunchConfiguration_cannotFindLaunchConfiguration;
4142
public static String OSGiLaunchConfiguration_selected;

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ 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_JUnitLaunchAndRuntimeMissmatch = The launch targets JUnit {0},\n\
29+
but JUnit {1} bundles are present in the runtime.\nTherefore this launch is expected to fail.\n\
30+
\nEither update the launch configuration to target JUnit {1},\n\
31+
or restrict the versions of JUnit Jupiter and JUnit Platform\n\
32+
by specifying corresponding version bounds\n\
33+
in your test-project to match only JUnit {0}.
2834

2935
OSGiLaunchConfiguration_cannotFindLaunchConfiguration=Cannot find the {0} OSGi framework.
3036
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)