1313 *******************************************************************************/
1414package org .eclipse .pde .internal .launching ;
1515
16+ import java .util .ArrayList ;
1617import java .util .HashMap ;
1718import java .util .LinkedHashMap ;
19+ import java .util .List ;
1820import java .util .Map ;
1921import java .util .Set ;
20- import java .util .stream .Collectors ;
2122
2223import org .eclipse .core .runtime .CoreException ;
2324import org .eclipse .core .runtime .IProgressMonitor ;
2425import org .eclipse .core .runtime .Status ;
2526import org .eclipse .debug .core .ILaunchConfiguration ;
27+ import org .eclipse .jdt .internal .junit .buildpath .BuildPathSupport ;
2628import org .eclipse .jdt .internal .junit .launcher .TestKindRegistry ;
2729import org .eclipse .osgi .service .resolver .BundleDescription ;
30+ import org .eclipse .osgi .service .resolver .ExportPackageDescription ;
2831import org .eclipse .osgi .util .NLS ;
2932import org .eclipse .pde .core .plugin .IPluginModelBase ;
3033import org .eclipse .pde .internal .launching .launcher .LaunchValidationOperation ;
31- import org .osgi .framework .Version ;
3234
3335public class JUnitLaunchValidationOperation extends LaunchValidationOperation {
3436
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- });
37+ private record JunitDependency (String fromBundle , String toBundle , int majorVersion ) {
38+ }
39+
40+ private static final String JUNIT_BUNDLE_PREFIX_ORBIT = "org.junit" ; //$NON-NLS-1$
41+ private static final String JUNIT_BUNDLE_PREFIX = "junit" ; //$NON-NLS-1$
42+
43+ private static final Map <String , String > JUNIT_BUNDLE_NAMES = junitBundleNames ();
44+ private static final Map <String , String > JUNIT_PACKAGE_TO_BUNDLE = junitPackageToBundle ();
3945
4046 private final Map <Object , Object []> fErrors = new HashMap <>(2 );
4147
@@ -58,17 +64,56 @@ private void checkJunitVersion(ILaunchConfiguration configuration, Set<IPluginMo
5864 if (testKind .isNull ()) {
5965 return ;
6066 }
61- Set <Version > junitPlatformBundlesVersions = junitPlatformBundleVersions (models );
6267 String testKindId = testKind .getId ();
6368 switch (testKindId ) {
6469 case TestKindRegistry .JUNIT3_TEST_KIND_ID , TestKindRegistry .JUNIT4_TEST_KIND_ID -> {
6570 } // nothing to check
6671 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 );
72+ List <JunitDependency > junitDependencies = new ArrayList <>();
73+ for (IPluginModelBase model : models ) {
74+ BundleDescription description = model .getBundleDescription ();
75+ String symbolicName = description .getSymbolicName ();
76+ // JUnit bundles depends on JUnit bundles, so don't report that
77+ if (symbolicName .startsWith (JUNIT_BUNDLE_PREFIX ) || symbolicName .startsWith (JUNIT_BUNDLE_PREFIX_ORBIT )) {
78+ continue ;
79+ }
80+ BundleDescription [] requires = description .getResolvedRequires ();
81+ for (BundleDescription require : requires ) {
82+ String junitBundleName = JUNIT_BUNDLE_NAMES .get (require .getSymbolicName ());
83+ if (junitBundleName != null ) {
84+ junitDependencies .add (new JunitDependency (symbolicName , junitBundleName , require .getVersion ().getMajor ()));
85+ }
86+ }
87+ ExportPackageDescription [] resolvedImports = description .getResolvedImports ();
88+ for (ExportPackageDescription resolvedImport : resolvedImports ) {
89+ String junitBundleName = JUNIT_PACKAGE_TO_BUNDLE .get (resolvedImport .getName ());
90+ if (junitBundleName != null ) {
91+ junitDependencies .add (new JunitDependency (symbolicName , junitBundleName , resolvedImport .getVersion ().getMajor ()));
92+ }
93+ }
94+ }
95+ JunitDependency junitJupiterEngine5 = null ;
96+ JunitDependency junitPlatformEngine6 = null ;
97+ for (JunitDependency dependency : junitDependencies ) {
98+ if (dependency .majorVersion == 6 && (BuildPathSupport .JUNIT_JUPITER_API .equals (dependency .toBundle ) || BuildPathSupport .JUNIT_JUPITER_ENGINE .equals (dependency .toBundle ))) {
99+ String message = NLS .bind (PDEMessages .JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch , 5 , 6 , dependency .fromBundle , dependency .toBundle );
100+ addError (message );
101+ }
102+ if (dependency .majorVersion == 5 && BuildPathSupport .JUNIT_JUPITER_ENGINE .equals (dependency .toBundle )) {
103+ junitJupiterEngine5 = dependency ;
104+ }
105+ if (dependency .majorVersion == 6 && BuildPathSupport .JUNIT_PLATFORM_ENGINE .equals (dependency .toBundle )) {
106+ junitPlatformEngine6 = dependency ;
107+ }
108+ }
109+ /*
110+ * Depending on junit-platform-engine 6.x causes problems only if junit-jupiter-engine 5.x is also depended on directly.
111+ * The dependency from junit-jupiter-api 5.x to junit-jupiter-engine 5.x doesn't interfere here.
112+ */
113+ if (junitJupiterEngine5 != null && junitPlatformEngine6 != null ) {
114+ String message = NLS .bind (PDEMessages .JUnitLaunchConfiguration_error_JUnitLaunchAndRuntimeMissmatch , 5 , 6 , junitPlatformEngine6 .fromBundle , junitPlatformEngine6 .toBundle );
70115 addError (message );
71- });
116+ }
72117 }
73118 default -> throw new CoreException (Status .error ("Unsupported test kind: " + testKindId )); //$NON-NLS-1$
74119 }
@@ -78,6 +123,27 @@ private void addError(String message) {
78123 fErrors .put (message .replaceAll ("\\ R" , " " ), null ); //$NON-NLS-1$//$NON-NLS-2$
79124 }
80125
126+ @ SuppressWarnings ("restriction" )
127+ private static Map <String , String > junitBundleNames () {
128+ Map <String , String > map = new HashMap <>();
129+ map .put ("org.junit.jupiter.api" , BuildPathSupport .JUNIT_JUPITER_API ); //$NON-NLS-1$
130+ map .put ("org.junit.jupiter.engine" , BuildPathSupport .JUNIT_JUPITER_ENGINE ); //$NON-NLS-1$
131+ map .put ("org.junit.platofrm.engine" , BuildPathSupport .JUNIT_PLATFORM_ENGINE ); //$NON-NLS-1$
132+ map .put (BuildPathSupport .JUNIT_JUPITER_API , BuildPathSupport .JUNIT_JUPITER_API );
133+ map .put (BuildPathSupport .JUNIT_JUPITER_ENGINE , BuildPathSupport .JUNIT_JUPITER_ENGINE );
134+ map .put (BuildPathSupport .JUNIT_PLATFORM_ENGINE , BuildPathSupport .JUNIT_PLATFORM_ENGINE );
135+ return map ;
136+ }
137+
138+ @ SuppressWarnings ("restriction" )
139+ private static Map <String , String > junitPackageToBundle () {
140+ Map <String , String > map = new HashMap <>();
141+ map .put ("org.junit.jupiter.api" , BuildPathSupport .JUNIT_JUPITER_API ); //$NON-NLS-1$
142+ map .put ("org.junit.jupiter.engine" , BuildPathSupport .JUNIT_JUPITER_ENGINE ); //$NON-NLS-1$
143+ map .put ("org.junit.platofrm.engine" , BuildPathSupport .JUNIT_PLATFORM_ENGINE ); //$NON-NLS-1$
144+ return map ;
145+ }
146+
81147 @ Override
82148 public boolean hasErrors () {
83149 return !fErrors .isEmpty ();
@@ -89,10 +155,4 @@ public Map<Object, Object[]> getInput() {
89155 map .putAll (fErrors );
90156 return map ;
91157 }
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- }
98158}
0 commit comments