Skip to content

Commit aa25966

Browse files
Copilotlaeubi
andcommitted
Implement JUnit version validation in LaunchValidationOperation
- Modified JUnitLaunchValidationOperation to call parent's run() first to resolve the state - Added checkForJUnit6InJUnit5Launch() to detect JUnit 6+ bundles in JUnit 5 launches - Added findBundleRequiringJUnit6() to identify which bundle is pulling in JUnit 6 - Updated error reporting to include the bundle causing the conflict - Added new message key JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch_withRequiringBundle - Merged parent validation errors with JUnit-specific errors in getInput() and hasErrors() This implements the validation as described in PR eclipse-pde#2092 comment #3489590138 Co-authored-by: laeubi <[email protected]>
1 parent 1feabb5 commit aa25966

File tree

3 files changed

+89
-22
lines changed

3 files changed

+89
-22
lines changed

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

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import java.util.LinkedHashMap;
1818
import java.util.Map;
1919
import java.util.Set;
20-
import java.util.stream.Collectors;
2120

2221
import org.eclipse.core.runtime.CoreException;
2322
import org.eclipse.core.runtime.IProgressMonitor;
@@ -32,11 +31,6 @@
3231

3332
public class JUnitLaunchValidationOperation extends LaunchValidationOperation {
3433

35-
private static final Set<String> JUNIT_PLATFORM_ENGINE_BUNLDES = Set.of(new String[] { //
36-
"junit-platform-engine", //$NON-NLS-1$
37-
"org.junit.platform.engine", //$NON-NLS-1$
38-
});
39-
4034
private final Map<Object, Object[]> fErrors = new HashMap<>(2);
4135

4236
public JUnitLaunchValidationOperation(ILaunchConfiguration configuration, Set<IPluginModelBase> models) {
@@ -45,54 +39,117 @@ public JUnitLaunchValidationOperation(ILaunchConfiguration configuration, Set<IP
4539

4640
@Override
4741
public void run(IProgressMonitor monitor) throws CoreException {
42+
// First run parent validation to resolve the state
43+
super.run(monitor);
44+
45+
// Then check for JUnit version conflicts in the resolved state
4846
try {
49-
checkJunitVersion(fLaunchConfiguration, fModels);
47+
checkJunitVersionConflicts(fLaunchConfiguration);
5048
} catch (CoreException e) {
5149
PDELaunchingPlugin.log(e);
5250
}
5351
}
5452

5553
@SuppressWarnings("restriction")
56-
private void checkJunitVersion(ILaunchConfiguration configuration, Set<IPluginModelBase> models) throws CoreException {
54+
private void checkJunitVersionConflicts(ILaunchConfiguration configuration) throws CoreException {
5755
org.eclipse.jdt.internal.junit.launcher.ITestKind testKind = org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration);
5856
if (testKind.isNull()) {
5957
return;
6058
}
61-
Set<Version> junitPlatformBundlesVersions = junitPlatformBundleVersions(models);
59+
6260
String testKindId = testKind.getId();
6361
switch (testKindId) {
6462
case TestKindRegistry.JUNIT3_TEST_KIND_ID, TestKindRegistry.JUNIT4_TEST_KIND_ID -> {
65-
} // nothing to check
63+
// nothing to check for JUnit 3 and 4
64+
}
6665
case TestKindRegistry.JUNIT5_TEST_KIND_ID -> {
67-
// JUnit 5 platform bundles have version range [1.0,2.0)
68-
junitPlatformBundlesVersions.stream().map(Version::getMajor).filter(i -> i.intValue() != 1).findFirst().ifPresent(otherVersion -> {
69-
String message = NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch, 5, otherVersion);
70-
addError(message);
71-
});
66+
checkForJUnit6InJUnit5Launch();
7267
}
7368
default -> throw new CoreException(Status.error("Unsupported test kind: " + testKindId)); //$NON-NLS-1$
7469
}
7570
}
71+
72+
/**
73+
* Check if JUnit 6+ bundles are included in a JUnit 5 launch.
74+
* This can cause runtime errors like "org.junit.jupiter.engine.JupiterTestEngine not a subtype".
75+
*/
76+
private void checkForJUnit6InJUnit5Launch() {
77+
if (getState() == null) {
78+
return;
79+
}
80+
81+
// Get all bundles in the resolved state
82+
BundleDescription[] bundles = getState().getBundles();
83+
84+
// Find all junit-jupiter-engine bundles with major version >= 6
85+
for (BundleDescription bundle : bundles) {
86+
if ("junit-jupiter-engine".equals(bundle.getSymbolicName())) { //$NON-NLS-1$
87+
Version version = bundle.getVersion();
88+
if (version.getMajor() >= 6) {
89+
// Found a JUnit 6+ bundle, now find which bundle required it
90+
String requiringBundle = findBundleRequiringJUnit6(bundles, bundle);
91+
String message;
92+
if (requiringBundle != null) {
93+
message = NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch_withRequiringBundle,
94+
new Object[] { Integer.valueOf(5), Integer.valueOf(version.getMajor()), requiringBundle });
95+
} else {
96+
message = NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch,
97+
Integer.valueOf(5), Integer.valueOf(version.getMajor()));
98+
}
99+
addError(message);
100+
}
101+
}
102+
}
103+
}
104+
105+
/**
106+
* Find which bundle is requiring a JUnit 6 bundle.
107+
* This helps users understand why JUnit 6 was included in their JUnit 5 launch.
108+
*
109+
* @param bundles all bundles in the resolved state
110+
* @param junitBundle the JUnit 6 bundle to find requirements for
111+
* @return the symbolic name of the bundle requiring the JUnit 6 bundle, or null if not found
112+
*/
113+
private String findBundleRequiringJUnit6(BundleDescription[] bundles, BundleDescription junitBundle) {
114+
for (BundleDescription bundle : bundles) {
115+
if (bundle.isResolved()) {
116+
// Check Require-Bundle dependencies
117+
BundleDescription[] requiredBundles = bundle.getResolvedRequires();
118+
for (BundleDescription required : requiredBundles) {
119+
if (required.equals(junitBundle)) {
120+
return bundle.getSymbolicName();
121+
}
122+
}
123+
124+
// Check Import-Package dependencies
125+
// If a bundle imports packages from junit-jupiter-engine, it contributes to pulling it in
126+
org.eclipse.osgi.service.resolver.ExportPackageDescription[] imports = bundle.getResolvedImports();
127+
for (org.eclipse.osgi.service.resolver.ExportPackageDescription export : imports) {
128+
if (export.getExporter().equals(junitBundle)) {
129+
return bundle.getSymbolicName();
130+
}
131+
}
132+
}
133+
}
134+
return null;
135+
}
76136

77137
private void addError(String message) {
78138
fErrors.put(message.replaceAll("\\R", " "), null); //$NON-NLS-1$//$NON-NLS-2$
79139
}
80140

81141
@Override
82142
public boolean hasErrors() {
83-
return !fErrors.isEmpty();
143+
return super.hasErrors() || !fErrors.isEmpty();
84144
}
85145

86146
@Override
87147
public Map<Object, Object[]> getInput() {
88148
Map<Object, Object[]> map = new LinkedHashMap<>();
149+
// Add parent validation errors first
150+
map.putAll(super.getInput());
151+
// Then add JUnit-specific validation errors
89152
map.putAll(fErrors);
90153
return map;
91154
}
92-
93-
private static Set<Version> junitPlatformBundleVersions(Set<IPluginModelBase> models) {
94-
return models.stream().map(IPluginModelBase::getBundleDescription) //
95-
.filter(d -> JUNIT_PLATFORM_ENGINE_BUNLDES.contains(d.getSymbolicName())) //
96-
.map(BundleDescription::getVersion).collect(Collectors.toSet());
97-
}
98155
}

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
@@ -37,6 +37,7 @@ public class PDEMessages extends NLS {
3737
public static String JUnitLaunchConfiguration_error_notaplugin;
3838
public static String JUnitLaunchConfiguration_error_missingPlugin;
3939
public static String JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch;
40+
public static String JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch_withRequiringBundle;
4041

4142
public static String OSGiLaunchConfiguration_cannotFindLaunchConfiguration;
4243
public static String OSGiLaunchConfiguration_selected;

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ Either update the launch configuration to target JUnit {1},\n\
3232
or restrict the versions of JUnit Jupiter and JUnit Platform\n\
3333
by specifying corresponding version bounds\n\
3434
in your test-project to match only JUnit {0}.
35+
JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch_withRequiringBundle = Launch targets JUnit {0} but contains JUnit {1} bundles.\n\
36+
Therefore this launch is expected to fail.\n\
37+
\n\
38+
The bundle ''{2}'' is pulling in JUnit {1}.\n\
39+
\n\
40+
Either update the launch configuration to target JUnit {1},\n\
41+
or restrict the versions of JUnit Jupiter and JUnit Platform\n\
42+
by specifying corresponding version bounds\n\
43+
in the ''{2}'' bundle or your test-project to match only JUnit {0}.
3544

3645
OSGiLaunchConfiguration_cannotFindLaunchConfiguration=Cannot find the {0} OSGi framework.
3746
OSGiLaunchConfiguration_selected=selected

0 commit comments

Comments
 (0)