|
16 | 16 |
|
17 | 17 | import java.util.ArrayList; |
18 | 18 | import java.util.Collection; |
19 | | -import java.util.Collections; |
| 19 | +import java.util.LinkedHashMap; |
20 | 20 | import java.util.LinkedHashSet; |
21 | 21 | import java.util.List; |
22 | 22 | import java.util.Map; |
| 23 | +import java.util.Map.Entry; |
| 24 | +import java.util.Optional; |
23 | 25 | import java.util.Set; |
24 | 26 |
|
25 | 27 | import org.eclipse.core.runtime.CoreException; |
26 | | -import org.eclipse.core.runtime.IStatus; |
27 | 28 | import org.eclipse.core.runtime.Status; |
28 | 29 | import org.eclipse.debug.core.ILaunchConfiguration; |
29 | 30 | import org.eclipse.osgi.service.resolver.BundleDescription; |
|
33 | 34 | import org.eclipse.pde.internal.core.DependencyManager; |
34 | 35 | import org.eclipse.pde.internal.core.PDECore; |
35 | 36 | import org.eclipse.pde.internal.launching.launcher.BundleLauncherHelper; |
| 37 | +import org.osgi.framework.Version; |
36 | 38 | import org.osgi.framework.VersionRange; |
37 | 39 | import org.osgi.framework.wiring.BundleRevision; |
38 | 40 |
|
39 | 41 | public class JUnitLaunchRequirements { |
40 | 42 |
|
41 | | - public static final String JUNIT4_RUNTIME_PLUGIN = "org.eclipse.jdt.junit4.runtime"; //$NON-NLS-1$ |
42 | | - public static final String JUNIT5_RUNTIME_PLUGIN = "org.eclipse.jdt.junit5.runtime"; //$NON-NLS-1$ |
| 43 | + public static final String JUNIT4_JDT_RUNTIME_PLUGIN = "org.eclipse.jdt.junit4.runtime"; //$NON-NLS-1$ |
| 44 | + public static final String JUNIT5_JDT_RUNTIME_PLUGIN = "org.eclipse.jdt.junit5.runtime"; //$NON-NLS-1$ |
43 | 45 |
|
44 | 46 | private static final VersionRange JUNIT5_VERSIONS = new VersionRange("[1, 5)"); //$NON-NLS-1$ |
45 | 47 |
|
46 | 48 | // we add launcher and jupiter.engine to support @RunWith(JUnitPlatform.class) |
47 | | - private static final String[] JUNIT5_RUN_WITH_PLUGINS = {"junit-platform-launcher", //$NON-NLS-1$ |
48 | | - "junit-jupiter-engine", //$NON-NLS-1$ |
49 | | - }; |
| 49 | + private static final Map<String, List<String>> JUNIT5_RUN_WITH_BUNDLES = new LinkedHashMap<>(); |
| 50 | + static { // consider JUnit bundle names from old Eclipse-Orbit times. Assume either only new or only old names are used. |
| 51 | + JUNIT5_RUN_WITH_BUNDLES.put("junit-platform-runner", List.of("junit-platform-launcher", "junit-jupiter-engine")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 52 | + JUNIT5_RUN_WITH_BUNDLES.put("org.junit.platform.runner", List.of("org.junit.platform.launcher", "org.junit.jupiter.engine")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 53 | + } |
50 | 54 |
|
51 | 55 | public static void addRequiredJunitRuntimePlugins(ILaunchConfiguration configuration, Map<String, List<IPluginModelBase>> allBundles, Map<IPluginModelBase, String> allModels) throws CoreException { |
52 | | - Collection<String> plugins = getRequiredJunitRuntimePlugins(configuration); |
53 | | - addPlugins(plugins, allBundles, allModels); |
54 | | - if (plugins.contains(JUNIT5_RUNTIME_PLUGIN) && (allBundles.containsKey("junit-platform-runner") || allBundles.containsKey("org.junit.platform.runner"))) { //$NON-NLS-1$ //$NON-NLS-2$ |
55 | | - Set<BundleDescription> descriptions = JUnitLaunchRequirements.junit5PlatformRequirements(); |
56 | | - Set<BundleDescription> junitRquirements = DependencyManager.findRequirementsClosure(descriptions); |
57 | | - addAbsentRequirements(junitRquirements, allBundles, allModels); |
| 56 | + Collection<String> runtimePlugins = getRequiredJunitRuntimeEclipsePlugins(configuration); |
| 57 | + |
| 58 | + Set<BundleDescription> addedRuntimeBundles = addAbsentRequirements(runtimePlugins, allBundles, allModels); |
| 59 | + Set<BundleDescription> runtimeRequirements = DependencyManager.findRequirementsClosure(addedRuntimeBundles); |
| 60 | + addAbsentRequirements(runtimeRequirements, allBundles, allModels); |
| 61 | + |
| 62 | + if (runtimePlugins.contains(JUNIT5_JDT_RUNTIME_PLUGIN)) { |
| 63 | + Optional<List<String>> runWithBundles = JUNIT5_RUN_WITH_BUNDLES.entrySet().stream().filter(e -> allBundles.containsKey(e.getKey())).findFirst().map(Entry::getValue); |
| 64 | + if (runWithBundles.isPresent()) { |
| 65 | + Set<BundleDescription> descriptions = findBundlesInTargetOrHost(runWithBundles.get(), JUNIT5_VERSIONS); |
| 66 | + Set<BundleDescription> junitRquirements = DependencyManager.findRequirementsClosure(descriptions); |
| 67 | + addAbsentRequirements(junitRquirements, allBundles, allModels); |
| 68 | + } |
58 | 69 | } |
59 | 70 | } |
60 | 71 |
|
61 | 72 | @SuppressWarnings("restriction") |
62 | | - public static Collection<String> getRequiredJunitRuntimePlugins(ILaunchConfiguration configuration) { |
| 73 | + public static Collection<String> getRequiredJunitRuntimeEclipsePlugins(ILaunchConfiguration configuration) { |
63 | 74 | org.eclipse.jdt.internal.junit.launcher.ITestKind testKind = org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants.getTestRunnerKind(configuration); |
64 | 75 | if (testKind.isNull()) { |
65 | | - return Collections.emptyList(); |
| 76 | + return List.of(); |
66 | 77 | } |
67 | 78 | List<String> plugins = new ArrayList<>(); |
68 | 79 | plugins.add("org.eclipse.pde.junit.runtime"); //$NON-NLS-1$ |
69 | | - |
70 | | - if (org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT4_TEST_KIND_ID.equals(testKind.getId())) { |
71 | | - plugins.add(JUNIT4_RUNTIME_PLUGIN); |
72 | | - } else if (org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT5_TEST_KIND_ID.equals(testKind.getId())) { |
73 | | - plugins.add(JUNIT5_RUNTIME_PLUGIN); |
| 80 | + switch (testKind.getId()) { |
| 81 | + case org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT3_TEST_KIND_ID -> { |
| 82 | + } // Nothing to add for JUnit-3 |
| 83 | + case org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT4_TEST_KIND_ID -> plugins.add(JUNIT4_JDT_RUNTIME_PLUGIN); |
| 84 | + case org.eclipse.jdt.internal.junit.launcher.TestKindRegistry.JUNIT5_TEST_KIND_ID -> plugins.add(JUNIT4_JDT_RUNTIME_PLUGIN); |
| 85 | + default -> throw new IllegalArgumentException("Unsupported junit test kind: " + testKind.getId()); //$NON-NLS-1$ |
74 | 86 | } |
75 | 87 | return plugins; |
76 | 88 | } |
77 | 89 |
|
78 | | - private static void addPlugins(Collection<String> plugins, Map<String, List<IPluginModelBase>> allBundles, Map<IPluginModelBase, String> allModels) throws CoreException { |
79 | | - Set<String> requiredPlugins = new LinkedHashSet<>(plugins); |
80 | | - |
| 90 | + private static Set<BundleDescription> addAbsentRequirements(Collection<String> requirements, Map<String, List<IPluginModelBase>> allBundles, Map<IPluginModelBase, String> allModels) throws CoreException { |
81 | 91 | Set<BundleDescription> addedRequirements = new LinkedHashSet<>(); |
82 | | - addAbsentRequirements(requiredPlugins, addedRequirements, allBundles, allModels); |
83 | | - |
84 | | - Set<BundleDescription> requirementsOfRequirements = DependencyManager.findRequirementsClosure(addedRequirements); |
85 | | - addAbsentRequirements(requirementsOfRequirements, allBundles, allModels); |
86 | | - } |
87 | | - |
88 | | - private static void addAbsentRequirements(Collection<String> requirements, Set<BundleDescription> addedRequirements, Map<String, List<IPluginModelBase>> allBundles, Map<IPluginModelBase, String> allModels) throws CoreException { |
89 | 92 | for (String id : requirements) { |
90 | 93 | List<IPluginModelBase> models = allBundles.computeIfAbsent(id, k -> new ArrayList<>()); |
91 | | - if (models.stream().noneMatch(m -> m.getBundleDescription().isResolved())) { |
92 | | - IPluginModelBase model = JUnitLaunchRequirements.findRequiredPluginInTargetOrHost(id); |
| 94 | + if (models.stream().noneMatch(p -> p.getBundleDescription().isResolved())) { |
| 95 | + IPluginModelBase model = findRequiredPluginInTargetOrHost(id, null); |
93 | 96 | models.add(model); |
94 | 97 | BundleLauncherHelper.addDefaultStartingBundle(allModels, model); |
95 | | - if (addedRequirements != null) { |
96 | | - addedRequirements.add(model.getBundleDescription()); |
97 | | - } |
| 98 | + addedRequirements.add(model.getBundleDescription()); |
98 | 99 | } |
99 | 100 | } |
| 101 | + return addedRequirements; |
100 | 102 | } |
101 | 103 |
|
102 | | - private static void addAbsentRequirements(Set<BundleDescription> toAdd, Map<String, List<IPluginModelBase>> allBundles, Map<IPluginModelBase, String> allModels) throws CoreException { |
103 | | - for (BundleDescription requirement : toAdd) { |
| 104 | + private static void addAbsentRequirements(Set<BundleDescription> requirements, Map<String, List<IPluginModelBase>> allBundles, Map<IPluginModelBase, String> allModels) throws CoreException { |
| 105 | + for (BundleRevision requirement : requirements) { |
104 | 106 | String id = requirement.getSymbolicName(); |
| 107 | + Version version = requirement.getVersion(); |
105 | 108 | List<IPluginModelBase> models = allBundles.computeIfAbsent(id, k -> new ArrayList<>()); |
106 | | - boolean replace = !models.isEmpty() && models.stream().noneMatch(m -> m.getBundleDescription().getVersion().equals(requirement.getVersion())); |
| 109 | + boolean replace = !models.isEmpty() && models.stream().noneMatch(m -> m.getBundleDescription().getVersion().equals(version)); |
107 | 110 | if (replace || models.stream().noneMatch(m -> m.getBundleDescription().isResolved())) { |
108 | | - IPluginModelBase model = JUnitLaunchRequirements.findRequiredPluginInTargetOrHost(requirement); |
| 111 | + IPluginModelBase model = findRequiredPluginInTargetOrHost(requirement.getSymbolicName(), new VersionRange(VersionRange.LEFT_OPEN, version, version, VersionRange.RIGHT_OPEN)); |
109 | 112 | if (replace) { |
110 | 113 | String startLevel = null; |
111 | 114 | for (IPluginModelBase m : models) { |
112 | 115 | startLevel = allModels.remove(m); |
113 | 116 | } |
114 | 117 | models.clear(); |
115 | | - allModels.put(model, startLevel); |
| 118 | + allModels.put(model, startLevel); //TODO: isn't this overwritten? Should it be retained or just ignored? |
116 | 119 | } |
117 | 120 | models.add(model); |
118 | 121 | BundleLauncherHelper.addDefaultStartingBundle(allModels, model); |
119 | 122 | } |
120 | 123 | } |
121 | 124 | } |
122 | 125 |
|
123 | | - public static Set<BundleDescription> junit5PlatformRequirements() throws CoreException { |
| 126 | + private static Set<BundleDescription> findBundlesInTargetOrHost(List<String> bundleIDs, VersionRange version) throws CoreException { |
124 | 127 | Set<BundleDescription> descriptions = new LinkedHashSet<>(); |
125 | | - for (String id : JUNIT5_RUN_WITH_PLUGINS) { |
126 | | - IPluginModelBase model = findRequiredPluginInTargetOrHost(id, JUNIT5_VERSIONS); |
| 128 | + for (String id : bundleIDs) { |
| 129 | + IPluginModelBase model = findRequiredPluginInTargetOrHost(id, version); |
127 | 130 | if (model != null) { |
128 | | - BundleDescription description = model.getBundleDescription(); |
129 | | - descriptions.add(description); |
| 131 | + descriptions.add(model.getBundleDescription()); |
130 | 132 | } |
131 | 133 | } |
132 | 134 | return descriptions; |
133 | 135 | } |
134 | 136 |
|
135 | | - public static IPluginModelBase findRequiredPluginInTargetOrHost(String id) throws CoreException { |
136 | | - return findRequiredPluginInTargetOrHost(id, PluginRegistry.findModel(id)); |
137 | | - } |
138 | | - |
139 | | - private static IPluginModelBase findRequiredPluginInTargetOrHost(String id, VersionRange versionRange) throws CoreException { |
140 | | - return findRequiredPluginInTargetOrHost(id, PluginRegistry.findModel(id, versionRange)); |
141 | | - } |
142 | | - |
143 | | - public static IPluginModelBase findRequiredPluginInTargetOrHost(BundleRevision bundleRevision) throws CoreException { |
144 | | - String id = bundleRevision.getSymbolicName(); |
145 | | - return findRequiredPluginInTargetOrHost(id, PluginRegistry.findModel(bundleRevision)); |
146 | | - } |
147 | | - |
148 | | - private static IPluginModelBase findRequiredPluginInTargetOrHost(String id, IPluginModelBase model) throws CoreException { |
| 137 | + private static IPluginModelBase findRequiredPluginInTargetOrHost(String id, VersionRange version) throws CoreException { |
| 138 | + IPluginModelBase model = version != null ? PluginRegistry.findModel(id, version) : PluginRegistry.findModel(id); |
149 | 139 | if (model == null || !model.getBundleDescription().isResolved()) { |
150 | 140 | // prefer bundle from host over unresolved bundle from target |
151 | | - model = PDECore.getDefault().findPluginInHost(id); |
| 141 | + model = PDECore.getDefault().findPluginInHost(id, version); |
152 | 142 | } |
153 | 143 | if (model == null) { |
154 | | - String message = NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_missingPlugin, id); |
155 | | - Status error = new Status(IStatus.ERROR, IPDEConstants.PLUGIN_ID, IStatus.OK, message, null); |
156 | | - throw new CoreException(error); |
| 144 | + throw new CoreException(Status.error(NLS.bind(PDEMessages.JUnitLaunchConfiguration_error_missingPlugin, id))); |
157 | 145 | } |
158 | 146 | return model; |
159 | 147 | } |
|
0 commit comments