From e180d1cf8a4d46ffe9a09cd0f55898aeb70ad4f2 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 * set TEST attributes when plugin name matches test_plugin_pattern --- .../ClasspathUpdaterTest.java | 209 ++++++++++++++++++ .../projects/classpathupdater/.classpath | 23 ++ .../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 | 21 ++ .../projects/classpathupdater/library.jar | Bin 0 -> 2171 bytes 9 files changed, 300 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 0000000000..9809960e8a --- /dev/null +++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/classpathupdater/ClasspathUpdaterTest.java @@ -0,0 +1,209 @@ +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.Arrays; +import java.util.Map; +import java.util.Optional; +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.jdt.core.IClasspathAttribute; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +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.core.ICoreConstants; +import org.eclipse.pde.internal.core.PDECore; +import org.eclipse.pde.internal.ui.wizards.tools.UpdateClasspathJob; +import org.eclipse.pde.ui.tests.util.ProjectUtils; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.TestRule; + +public class ClasspathUpdaterTest { + + private static IProject project; + private static IJavaProject jProject; + + private static IClasspathEntry[] originalClasspath; + private static String originalTestPluginPattern; + private static Boolean expectIsTest; + @ClassRule + public static final TestRule CLEAR_WORKSPACE = ProjectUtils.DELETE_ALL_WORKSPACE_PROJECTS_BEFORE_AND_AFTER; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + project = ProjectUtils.importTestProject("tests/projects/classpathupdater"); + assertTrue("Project was not created", project.exists()); + jProject = JavaCore.create(project); + originalClasspath = jProject.getRawClasspath(); + originalTestPluginPattern = PDECore.getDefault().getPreferencesManager() + .getString(ICoreConstants.TEST_PLUGIN_PATTERN); + expectIsTest = null; + } + + @After + public void restoreOriginalClasspath() throws Exception { + jProject.setRawClasspath(originalClasspath, null); + } + + @After + public void restoreOriginalTestPluginPattern() { + PDECore.getDefault().getPreferencesManager().setValue(ICoreConstants.TEST_PLUGIN_PATTERN, + originalTestPluginPattern); + expectIsTest = null; + } + + private void setTestPluginPattern() { + PDECore.getDefault().getPreferencesManager().setValue(ICoreConstants.TEST_PLUGIN_PATTERN, project.getName()); + expectIsTest = Boolean.TRUE; + } + + @Test + public void test_PreserveAttributes() throws Exception { + 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); + assertClasspathAttribute("src", IClasspathAttribute.TEST, true, Boolean::valueOf); + assertClasspathProperty("tests", "exported=false", e -> !e.isExported()); + assertClasspathAttribute("tests", IClasspathAttribute.IGNORE_OPTIONAL_PROBLEMS, null, Boolean::valueOf); + assertClasspathAttribute("tests", IClasspathAttribute.TEST, expectIsTest, Boolean::valueOf); + assertClasspathOrder("A.jar", "src", "org.eclipse.pde.core.requiredPlugins", "JavaSE-17", "SOMEVAR", + "library.jar", "tests"); + } + + @Test + public void test_PreserveAttributes_WithTestPluginName() throws Exception { + setTestPluginPattern(); + test_PreserveAttributes(); + } + + @Test + public void test_CreateFromScratch() throws Exception { + 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))); + assertClasspathProperty("src", "exported=false", e -> !e.isExported()); + assertClasspathAttribute("src", IClasspathAttribute.IGNORE_OPTIONAL_PROBLEMS, null, Boolean::valueOf); + assertClasspathAttribute("src", IClasspathAttribute.TEST, expectIsTest, Boolean::valueOf); + assertClasspathProperty("tests", "exported=false", e -> !e.isExported()); + assertClasspathAttribute("tests", IClasspathAttribute.IGNORE_OPTIONAL_PROBLEMS, null, Boolean::valueOf); + assertClasspathAttribute("tests", IClasspathAttribute.TEST, expectIsTest, Boolean::valueOf); + assertClasspathOrder("JavaSE-17", "org.eclipse.pde.core.requiredPlugins", "library.jar", "A.jar", "src", + "tests"); + } + + @Test + public void test_CreateFromScatch_WithTestPluginName() throws Exception { + setTestPluginPattern(); + test_CreateFromScratch(); + } + + @Test + public void test_ChangeSourceAttachment() throws Exception { + Map sourceMap = Map.of( // + "A.jar", IPath.fromOSString("library.jar"), // + "library.jar", IPath.fromOSString("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); + assertClasspathAttribute("src", IClasspathAttribute.TEST, true, Boolean::valueOf); + assertClasspathProperty("tests", "exported=false", e -> !e.isExported()); + assertClasspathAttribute("tests", IClasspathAttribute.IGNORE_OPTIONAL_PROBLEMS, null, Boolean::valueOf); + assertClasspathAttribute("tests", IClasspathAttribute.TEST, expectIsTest, Boolean::valueOf); + assertClasspathOrder("A.jar", "src", "org.eclipse.pde.core.requiredPlugins", "JavaSE-17", "SOMEVAR", + "library.jar", "tests"); + } + + @Test + public void test_ChangeSourceAttachment_WithTestPluginName() throws Exception { + setTestPluginPattern(); + test_ChangeSourceAttachment(); + } + + 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 { + IClasspathEntry entry = findClasspathEntry(entryName); + assertTrue("Classpath entry for '" + entryName + "' has not set '" + expectedValue + "'", checker.test(entry)); + } + + private void assertClasspathOrder(String... names) throws Exception { + var actualNames = Arrays.stream(jProject.getRawClasspath()).map(e -> e.getPath().lastSegment()).toList(); + assertEquals(Arrays.asList(names), actualNames); + } + + private IClasspathEntry findClasspathEntry(String name) throws JavaModelException { + Optional entry = Arrays.stream(jProject.getRawClasspath()) + .filter(e -> name.equals(e.getPath().lastSegment())).findFirst(); + assertTrue("Classpath entry for " + name + " is missing", entry.isPresent()); + return entry.get(); + } + + 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 0000000000..668576bd95 --- /dev/null +++ b/ui/org.eclipse.pde.ui.tests/tests/projects/classpathupdater/.classpath @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + 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 0000000000..1012ffa778 --- /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 0000000000..62ef3488cc --- /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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