From 159cbf2dcb90985c630590bda95fc6d6c163b2cb Mon Sep 17 00:00:00 2001 From: Michael Haubenwallner Date: Wed, 8 Mar 2023 15:35:59 +0100 Subject: [PATCH] ClasspathComputer: add tests for classpath computation Failing tests for these issues: * erroneous exception "Build path contains duplicate entry" * updating source attachment changed unrelated attributes * failed to preserve some existing attributes * failed to preserve entries of kind="var" * failed to preserve existing order * UpdateClasspathJob returned CANCEL on success Additional tests for existing behavior: * from scratch, create lib entries with exported="true" * from scratch, create classpath in some specific order --- .../ClasspathUpdaterTest.java | 152 ++++++++++++++++++ .../projects/classpathupdater/.classpath | 22 +++ .../tests/projects/classpathupdater/.project | 29 ++++ .../.settings/org.eclipse.jdt.core.prefs | 9 ++ .../tests/projects/classpathupdater/A.jar | Bin 0 -> 2171 bytes .../tests/projects/classpathupdater/Asrc.zip | Bin 0 -> 2171 bytes .../classpathupdater/META-INF/MANIFEST.MF | 9 ++ .../classpathupdater/build.properties | 18 +++ .../projects/classpathupdater/library.jar | Bin 0 -> 2171 bytes 9 files changed, 239 insertions(+) create mode 100644 ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathupdater/ClasspathUpdaterTest.java create mode 100644 ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.classpath create mode 100644 ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.project create mode 100644 ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.settings/org.eclipse.jdt.core.prefs create mode 100644 ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/A.jar create mode 100644 ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/Asrc.zip create mode 100644 ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/META-INF/MANIFEST.MF create mode 100644 ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/build.properties create mode 100644 ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/library.jar diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathupdater/ClasspathUpdaterTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathupdater/ClasspathUpdaterTest.java new file mode 100644 index 00000000000..e56182575d0 --- /dev/null +++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathupdater/ClasspathUpdaterTest.java @@ -0,0 +1,152 @@ +package org.eclipse.pde.ui.tests.classpathupdater; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.core.*; +import org.eclipse.pde.core.plugin.IPluginModelBase; +import org.eclipse.pde.core.plugin.PluginRegistry; +import org.eclipse.pde.internal.core.ClasspathComputer; +import org.eclipse.pde.internal.ui.wizards.tools.UpdateClasspathJob; +import org.eclipse.pde.ui.tests.util.ProjectUtils; +import org.junit.*; + +public class ClasspathUpdaterTest { + + private static IProject project; + private static IJavaProject jProject; + + private static IClasspathEntry[] originalClasspath; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + project = ProjectUtils.importTestProject("tests/projects/classpathupdater"); + jProject = JavaCore.create(project); + originalClasspath = jProject.getRawClasspath(); + } + + @After + public void restoreOriginalClasspath() throws Exception { + jProject.setRawClasspath(originalClasspath, null); + } + + @Test + public void testUpdateClasspath_PreserveAttributes() throws Exception { + assertTrue("Project was not created", project.exists()); + + runUpdateClasspathJob(); + assertClasspathAttribute("JavaSE-17", IClasspathAttribute.MODULE, true, Boolean::valueOf); + assertClasspathAttribute("library.jar", IClasspathAttribute.TEST, true, Boolean::valueOf); + assertClasspathProperty("library.jar", "exported=true", (e) -> e.isExported()); + assertClasspathProperty("library.jar", "no source", (e) -> e.getSourceAttachmentPath() == null); + assertClasspathAttribute("A.jar", IClasspathAttribute.TEST, null, Boolean::valueOf); + assertClasspathProperty("A.jar", "exported=false", (e) -> !e.isExported()); + assertClasspathProperty("A.jar", "default source", + (e) -> "Asrc.zip".equals(nullOr(e.getSourceAttachmentPath(), IPath::lastSegment))); + assertClasspathProperty("src", "exported=false", (e) -> !e.isExported()); + assertClasspathAttribute("src", IClasspathAttribute.IGNORE_OPTIONAL_PROBLEMS, true, Boolean::valueOf); + assertClasspathOrder("A.jar", "src", "org.eclipse.pde.core.requiredPlugins", "JavaSE-17", "SOMEVAR", + "library.jar"); + } + + @Test + public void testUpdateClasspath_CreateFromScratch() throws Exception { + assertTrue("Project was not created", project.exists()); + jProject.setRawClasspath(new IClasspathEntry[0], null); + + runUpdateClasspathJob(); + assertClasspathAttribute("JavaSE-17", IClasspathAttribute.MODULE, null, Boolean::valueOf); + assertClasspathAttribute("library.jar", IClasspathAttribute.TEST, null, Boolean::valueOf); + assertClasspathProperty("library.jar", "exported=true", (e) -> e.isExported()); + assertClasspathProperty("library.jar", "no source", (e) -> e.getSourceAttachmentPath() == null); + assertClasspathAttribute("A.jar", IClasspathAttribute.TEST, null, Boolean::valueOf); + assertClasspathProperty("A.jar", "exported=true", (e) -> e.isExported()); + assertClasspathProperty("A.jar", "default source", + (e) -> "Asrc.zip".equals(nullOr(e.getSourceAttachmentPath(), IPath::lastSegment))); + assertClasspathOrder("JavaSE-17", "org.eclipse.pde.core.requiredPlugins", "library.jar", "A.jar"); + } + + @Test + public void testClasspathComputer_ChangeSourceAttachment() throws Exception { + assertTrue("Project was not created", project.exists()); + + Map sourceMap = new HashMap<>(); + sourceMap.put("A.jar", new Path("library.jar")); + sourceMap.put("library.jar", new Path("A.jar")); + IPluginModelBase model = PluginRegistry.findModel(project.getProject()); + + IClasspathEntry[] cp = ClasspathComputer.getClasspath(project, model, sourceMap, false, false); + jProject.setRawClasspath(cp, null); + + assertClasspathAttribute("JavaSE-17", IClasspathAttribute.MODULE, true, Boolean::valueOf); + assertClasspathAttribute("library.jar", IClasspathAttribute.TEST, true, Boolean::valueOf); + assertClasspathProperty("library.jar", "exported=true", (e) -> e.isExported()); + assertClasspathProperty("library.jar", "overridden source", + (e) -> "A.jar".equals(nullOr(e.getSourceAttachmentPath(), IPath::lastSegment))); + assertClasspathAttribute("A.jar", IClasspathAttribute.TEST, null, Boolean::valueOf); + assertClasspathProperty("A.jar", "exported=false", (e) -> !e.isExported()); + assertClasspathProperty("A.jar", "overridden source", + (e) -> "library.jar".equals(nullOr(e.getSourceAttachmentPath(), IPath::lastSegment))); + assertClasspathProperty("src", "exported=false", (e) -> !e.isExported()); + assertClasspathAttribute("src", IClasspathAttribute.IGNORE_OPTIONAL_PROBLEMS, true, Boolean::valueOf); + assertClasspathOrder("A.jar", "src", "org.eclipse.pde.core.requiredPlugins", "JavaSE-17", "SOMEVAR", + "library.jar"); + } + + private void runUpdateClasspathJob() throws InterruptedException { + IPluginModelBase model = PluginRegistry.findModel(project.getProject()); + UpdateClasspathJob job = new UpdateClasspathJob(new IPluginModelBase[] { model }); + job.schedule(); + job.join(); + assertTrue("Update Classpath Job failed", job.getResult().isOK()); + } + + private void assertClasspathAttribute(String entryName, String attrName, T expectedValue, + Function parser) throws JavaModelException { + IClasspathEntry entry = findClasspathEntry(entryName); + assertNotNull("Classpath entry for " + entryName + " is missing", entry); + String attrValue = findClasspathAttributeValue(entry, attrName); + T current = attrValue != null ? parser.apply(attrValue) : null; // null: attribute not set + assertEquals("Classpath entry for '" + entry.getPath().lastSegment() + "': attribute '" + attrName + + "' is not '" + expectedValue + "'", expectedValue, current); + } + + private String findClasspathAttributeValue(IClasspathEntry entry, String name) { + return Arrays.stream(entry.getExtraAttributes()) // + .filter(a -> name.equals(a.getName())).map(IClasspathAttribute::getValue) // + .findFirst().orElse(null); + } + + private void assertClasspathProperty(String entryName, String expectedValue, Predicate checker) + throws JavaModelException { + String title = "Classpath entry for '" + entryName + "'"; + IClasspathEntry entry = findClasspathEntry(entryName); + assertTrue(title + " is missing", entry != null); + assertTrue(title + " has not set '" + expectedValue + "'", checker.test(entry)); + } + + private void assertClasspathOrder(String... names) throws Exception { + IClasspathEntry[] rawClasspath = jProject.getRawClasspath(); + assertEquals("Classpath has wrong number of entries", names.length, rawClasspath.length); + for (int i = 0; i < names.length; i++) { + assertEquals("Classpath has wrong order", names[i], rawClasspath[i].getPath().lastSegment()); + } + } + + private IClasspathEntry findClasspathEntry(String entryName) throws JavaModelException { + return Arrays.stream(jProject.getRawClasspath()) // + .filter(e -> entryName.equals(e.getPath().lastSegment())) // + .findFirst().orElse(null); + } + + private static R nullOr(T obj, Function f) { + return obj == null ? null : f.apply(obj); + } +} diff --git a/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.classpath b/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.classpath new file mode 100644 index 00000000000..5bccae7fc10 --- /dev/null +++ b/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.classpath @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.project b/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.project new file mode 100644 index 00000000000..1012ffa778b --- /dev/null +++ b/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.project @@ -0,0 +1,29 @@ + + + classpathupdater + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.ui.tests.testNature + + diff --git a/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.settings/org.eclipse.jdt.core.prefs b/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..62ef3488cc0 --- /dev/null +++ b/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,9 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/A.jar b/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/A.jar new file mode 100644 index 0000000000000000000000000000000000000000..74d8b4490d2c9f1d076ca89a9e262bb31bb1517e GIT binary patch literal 2171 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