diff --git a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/UnifiedTree.java b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/UnifiedTree.java index c610492bd69..5881c153842 100644 --- a/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/UnifiedTree.java +++ b/resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/UnifiedTree.java @@ -438,9 +438,6 @@ private static class PatternHolder { //Pattern: A UNIX or Windows relative path that just points backward static final Pattern TRIVIAL_SYMLINK_PATTERN = Pattern.compile( // Platform.OS.isWindows() ? "\\.[.\\\\]*" : "\\.[./]*"); //$NON-NLS-1$//$NON-NLS-2$ - - static final Pattern REPEATING_BACKWARDS_PATTERN = Pattern.compile( // - Platform.OS.isWindows() ? "(\\.\\.\\\\)+.*" : "(\\.\\./)+.*"); //$NON-NLS-1$//$NON-NLS-2$ } /** @@ -522,20 +519,10 @@ private boolean isRecursiveLink(IFileStore parentStore, IFileInfo localInfo) { Path realParentPath = parent.toRealPath(); if (disable_advanced_recursive_link_checks) { // Multiple ../ backwards links can go outside the project tree - if (linkTarget != null && PatternHolder.REPEATING_BACKWARDS_PATTERN.matcher(linkTarget).matches()) { - Path targetPath = parent.resolve(linkTarget).normalize(); - - // Recursive if literal target points to the literal parent of this tree - if (parent.normalize().startsWith(targetPath)) { + if (linkTarget != null) { + if (isRecursiveBackwardsLink(realParentPath, linkTarget)) { return true; } - - // Recursive if resolved target points to the resolved parent of this tree - Path realTargetPath = targetPath.toRealPath(); - if (realParentPath.startsWith(realTargetPath)) { - return true; - } - // If link is outside the project tree, consider as non recursive // The link still can create recursion in the tree, but we can't detect it here. } @@ -573,6 +560,51 @@ private boolean isRecursiveLink(IFileStore parentStore, IFileInfo localInfo) { return false; } + /** + * @param realParentPath real parent path object obtained as a result + * of @code{Path.toRealPath()} + * @param linkTarget the link target path as a string, may be relative or + * absolute + * @return true if the given target points backwards recursively to the given + * parent path + * @throws IOException + */ + private static boolean isRecursiveBackwardsLink(Path realParentPath, String linkTarget) + throws IOException { + // Cheap test first: literal target points to the literal parent + Path normalizedLink = realParentPath.resolve(linkTarget).normalize(); + if (realParentPath.startsWith(normalizedLink)) { + return true; + } + // Next check costs more time because it does real IO when resolving paths + Path realTarget = normalizedLink.toRealPath(); + if (realParentPath.startsWith(realTarget)) { + return true; + } + return false; + } + + /** + * Disable or enable advanced recursive link checks. Advanced link checks may + * hide valid directories in some cases, see bug 537449. + * + * @param enable true to enable advanced recursive link checks, + * false to disable them. + */ + public static void enableAdvancedRecursiveLinkChecks(boolean enable) { + disable_advanced_recursive_link_checks = !enable; + } + + /** + * Returns whether advanced recursive link checks are enabled. + * + * @return true if advanced recursive link checks are enabled, + * false otherwise. + */ + public static boolean isAdvancedRecursiveLinkChecksEnabled() { + return !disable_advanced_recursive_link_checks; + } + protected boolean isValidLevel(int currentLevel, int depth) { return switch (depth) { case IResource.DEPTH_INFINITE -> true; diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/SymlinkResourceTest.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/SymlinkResourceTest.java index 7f7310fb29f..d121db58b7a 100644 --- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/SymlinkResourceTest.java +++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/internal/localstore/SymlinkResourceTest.java @@ -21,28 +21,33 @@ import static org.eclipse.core.tests.resources.ResourceTestUtil.createInWorkspace; import static org.eclipse.core.tests.resources.ResourceTestUtil.createTestMonitor; import static org.eclipse.core.tests.resources.ResourceTestUtil.waitForRefresh; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.internal.localstore.UnifiedTree; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; -import org.eclipse.core.tests.resources.WorkspaceTestRule; -import org.junit.Rule; -import org.junit.Test; - +import org.eclipse.core.runtime.Platform.OS; +import org.eclipse.core.tests.resources.util.WorkspaceResetExtension; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@ExtendWith(WorkspaceResetExtension.class) public class SymlinkResourceTest { - @Rule - public WorkspaceTestRule workspaceRule = new WorkspaceTestRule(); - private void mkLink(IFileStore dir, String src, String tgt, boolean isDir) throws CoreException, IOException { createSymLink(dir.toLocalFile(EFS.NONE, createTestMonitor()), src, tgt, isDir); } @@ -70,6 +75,88 @@ protected void createBug358830Structure(IFileStore rootDir) throws CoreException mkLink(folderA, "link", IPath.fromOSString("../").toOSString(), true); } + /** + * Test a case of both recursive and non recursive symbolic links that uncovered + * issue described in GitHub bug + * 2220. + * + *
{@code
+	 *      /A/B -> /X/Y/Z  	(B is symbolic link as precondition)
+	 *      /A/B/C/D -> ../../D (non-recursive)
+	 *      /A/B/C/E -> ../../Z (recursive)
+	 * }
+ * + * The starting path /A/B/C is already based on link. The real path of start is + * /X/Y/Z/C so ../../Z points (recursive) to /X/Y/Z. /X/Y/D and /X/Y/Z is what + * we expect to resolve but we fail in both cases with NoSuchFileException. + */ + @ParameterizedTest + @ValueSource(booleans = { false, true }) + public void testGithubBug2220(boolean useAdvancedLinkCheck) throws Exception { + assumeTrue(canCreateSymLinks(), "only relevant for platforms supporting symbolic links"); + assumeTrue(!OS.isWindows(), "Windows file system handles recursive links differently"); + final boolean originalValue = UnifiedTree.isAdvancedRecursiveLinkChecksEnabled(); + try { + UnifiedTree.enableAdvancedRecursiveLinkChecks(useAdvancedLinkCheck); + IProject project = getWorkspace().getRoot().getProject("testGithubBug2220"); + createInWorkspace(project); + + /* Re-use projects which are cleaned up automatically */ + getWorkspace().run((IWorkspaceRunnable) monitor -> { + /* delete open project because we must re-open with BACKGROUND_REFRESH */ + project.delete(IResource.NEVER_DELETE_PROJECT_CONTENT, createTestMonitor()); + project.create(null); + try { + createGithubBug2220Structure(EFS.getStore(project.getLocationURI())); + } catch (IOException e) { + throw new IllegalStateException("unexpected IOException occurred", e); + } + // Bug only happens with BACKGROUND_REFRESH. + project.open(IResource.BACKGROUND_REFRESH, createTestMonitor()); + }, null); + + // wait for BACKGROUND_REFRESH to complete. + waitForRefresh(); + project.accept(new IResourceVisitor() { + int resourceCount = 0; + + @Override + public boolean visit(IResource resource) { + resourceCount++; + // We have 1 root + .settings + prefs + + .project + 10 elements --> 14 elements + // to visit at most + System.out.println(resourceCount + " visited: " + resource.getFullPath()); + assertTrue(resourceCount <= 15, "Expected max 15 elements to visit, got: " + resourceCount); + return true; + } + }); + } finally { + UnifiedTree.enableAdvancedRecursiveLinkChecks(originalValue); + } + } + + /** + *
{@code
+	 *      /A/B -> /X/Y/Z  	(B is symbolic link as precondition)
+	 *      /A/B/C/D -> ../../D (non-recursive)
+	 *      /A/B/C/E -> ../../Z (recursive)
+	 * }
+ * + * The starting path /A/B/C is already based on link. The real path of start is + * /X/Y/Z/C so ../../Z points (recursive) to /X/Y/Z. + */ + protected void createGithubBug2220Structure(IFileStore rootDir) throws CoreException, IOException { + Path root = rootDir.toLocalFile(EFS.NONE, createTestMonitor()).toPath(); + Files.createDirectories(root.resolve("A")); + Files.createDirectories(root.resolve("X/Y/Z")); + Files.createDirectories(root.resolve("X/Y/D")); + Files.createSymbolicLink(root.resolve("A/B"), root.resolve("X/Y/Z")); + Files.createDirectories(root.resolve("A/B/C")); + Files.createSymbolicLink(root.resolve("A/B/C/D"), Paths.get("../../D")); + Files.createSymbolicLink(root.resolve("A/B/C/E"), Paths.get("../../Z")); + } + /** * Test a very specific case of mutually recursive symbolic links: *
 {@code
@@ -85,7 +172,7 @@ protected void createBug358830Structure(IFileStore rootDir) throws CoreException
 	 */
 	@Test
 	public void testBug232426() throws Exception {
-		assumeTrue("only relevant for platforms supporting symbolic links", canCreateSymLinks());
+		assumeTrue(canCreateSymLinks(), "only relevant for platforms supporting symbolic links");
 
 		IProject project = getWorkspace().getRoot().getProject("Project");
 		createInWorkspace(project);
@@ -118,36 +205,42 @@ public boolean visit(IResource resource) {
 		});
 	}
 
-	@Test
-	public void testBug358830() throws Exception {
-		assumeTrue("only relevant for platforms supporting symbolic links", canCreateSymLinks());
-
-		IProject project = getWorkspace().getRoot().getProject("Project");
-		createInWorkspace(project);
-		/* Re-use projects which are cleaned up automatically */
-		getWorkspace().run((IWorkspaceRunnable) monitor -> {
-			/* delete open project because we must re-open with BACKGROUND_REFRESH */
-			project.delete(IResource.NEVER_DELETE_PROJECT_CONTENT, createTestMonitor());
-			project.create(null);
-			try {
-				createBug358830Structure(EFS.getStore(project.getLocationURI()));
-			} catch (IOException e) {
-				throw new IllegalStateException("unexpected IOException occurred", e);
-			}
-			project.open(IResource.BACKGROUND_REFRESH, createTestMonitor());
-		}, null);
-
-		//wait for BACKGROUND_REFRESH to complete.
-		waitForRefresh();
-		final int resourceCount[] = new int[] {0};
-		project.accept(resource -> {
-			resourceCount[0]++;
-			return true;
-		});
-		// We have 1 root + 1 folder + 1 file (.project)
-		// + .settings / resources prefs
-		// --> 5 elements to visit
-		assertEquals(5, resourceCount[0]);
+	@ParameterizedTest
+	@ValueSource(booleans = { false, true })
+	public void testBug358830(boolean useAdvancedLinkCheck) throws Exception {
+		assumeTrue(canCreateSymLinks(), "only relevant for platforms supporting symbolic links");
+		final boolean originalValue = UnifiedTree.isAdvancedRecursiveLinkChecksEnabled();
+		try {
+			UnifiedTree.enableAdvancedRecursiveLinkChecks(useAdvancedLinkCheck);
+			IProject project = getWorkspace().getRoot().getProject("Project");
+			createInWorkspace(project);
+			/* Re-use projects which are cleaned up automatically */
+			getWorkspace().run((IWorkspaceRunnable) monitor -> {
+				/* delete open project because we must re-open with BACKGROUND_REFRESH */
+				project.delete(IResource.NEVER_DELETE_PROJECT_CONTENT, createTestMonitor());
+				project.create(null);
+				try {
+					createBug358830Structure(EFS.getStore(project.getLocationURI()));
+				} catch (IOException e) {
+					throw new IllegalStateException("unexpected IOException occurred", e);
+				}
+				project.open(IResource.BACKGROUND_REFRESH, createTestMonitor());
+			}, null);
+
+			// wait for BACKGROUND_REFRESH to complete.
+			waitForRefresh();
+			final int resourceCount[] = new int[] { 0 };
+			project.accept(resource -> {
+				resourceCount[0]++;
+				return true;
+			});
+			// We have 1 root + 1 folder + 1 file (.project)
+			// + .settings / resources prefs
+			// --> 5 elements to visit
+			assertEquals(5, resourceCount[0]);
+		} finally {
+			UnifiedTree.enableAdvancedRecursiveLinkChecks(originalValue);
+		}
 	}
 
 }
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_185247_LinuxTests.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_185247_LinuxTests.java
index 274fe6913c9..c4dce863533 100644
--- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_185247_LinuxTests.java
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_185247_LinuxTests.java
@@ -11,10 +11,10 @@
 package org.eclipse.core.tests.resources.regression;
 
 import static org.eclipse.core.tests.resources.ResourceTestUtil.createTestMonitor;
-import static org.junit.Assume.assumeTrue;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 import java.io.File;
 import java.io.IOException;
@@ -26,6 +26,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import org.eclipse.core.internal.localstore.UnifiedTree;
 import org.eclipse.core.internal.resources.ProjectDescription;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectDescription;
@@ -38,10 +39,11 @@
 import org.eclipse.core.runtime.URIUtil;
 import org.eclipse.core.tests.resources.util.WorkspaceResetExtension;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestInfo;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 /**
  * Test cases for symbolic links in projects.
@@ -56,7 +58,7 @@ public class Bug_185247_LinuxTests {
 
 	@BeforeEach
 	public void setUp(TestInfo testInfo) throws Exception {
-		assumeTrue("only relevant on Linux", OS.isLinux());
+		assumeTrue(OS.isLinux(), "only relevant on Linux");
 
 		testMethodName = testInfo.getTestMethod().get().getName();
 		IPath randomLocation = IPath.fromPath(tempDirectory);
@@ -74,34 +76,45 @@ private void extractTestCasesArchive(IPath outputLocation) throws Exception {
 		unzip(archive, outputLocation.toFile());
 	}
 
-	@Test
-	public void test1_trivial() throws Exception {
-		runProjectTestCase();
+	@ParameterizedTest
+	@ValueSource(booleans = { false, true })
+	public void test1_trivial(boolean useAdvancedLinkCheck) throws Exception {
+		runProjectTestCase(useAdvancedLinkCheck);
 	}
 
-	@Test
-	public void test2_mutual() throws Exception {
-		runProjectTestCase();
+	@ParameterizedTest
+	@ValueSource(booleans = { false, true })
+	public void test2_mutual(boolean useAdvancedLinkCheck) throws Exception {
+		runProjectTestCase(useAdvancedLinkCheck);
 	}
 
-	@Test
-	public void test3_outside_tree() throws Exception {
-		runProjectTestCase();
+	@ParameterizedTest
+	@ValueSource(booleans = { false, true })
+	public void test3_outside_tree(boolean useAdvancedLinkCheck) throws Exception {
+		runProjectTestCase(useAdvancedLinkCheck);
 	}
 
-	@Test
-	public void test5_transitive_mutual() throws Exception {
-		runProjectTestCase();
+	@ParameterizedTest
+	@ValueSource(booleans = { false, true })
+	public void test5_transitive_mutual(boolean useAdvancedLinkCheck) throws Exception {
+		runProjectTestCase(useAdvancedLinkCheck);
 	}
 
-	@Test
-	public void test6_nonrecursive() throws Exception {
-		runProjectTestCase();
+	@ParameterizedTest
+	@ValueSource(booleans = { false, true })
+	public void test6_nonrecursive(boolean useAdvancedLinkCheck) throws Exception {
+		runProjectTestCase(useAdvancedLinkCheck);
 	}
 
-	private void runProjectTestCase() throws Exception {
-		// refresh should hang, if bug 105554 re-occurs
-		importProjectAndRefresh(testMethodName);
+	private void runProjectTestCase(boolean useAdvancedLinkCheck) throws Exception {
+		final boolean originalValue = UnifiedTree.isAdvancedRecursiveLinkChecksEnabled();
+		try {
+			UnifiedTree.enableAdvancedRecursiveLinkChecks(useAdvancedLinkCheck);
+			// refresh should hang, if bug 105554 re-occurs
+			importProjectAndRefresh(testMethodName);
+		} finally {
+			UnifiedTree.enableAdvancedRecursiveLinkChecks(originalValue);
+		}
 	}
 
 	private void importProjectAndRefresh(String projectName) throws Exception {
diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_185247_recursiveLinks.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_185247_recursiveLinks.java
index 34487877e93..3875bb952b1 100644
--- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_185247_recursiveLinks.java
+++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/regression/Bug_185247_recursiveLinks.java
@@ -13,8 +13,8 @@
 import static org.eclipse.core.tests.harness.FileSystemHelper.canCreateSymLinks;
 import static org.eclipse.core.tests.harness.FileSystemHelper.createSymLink;
 import static org.eclipse.core.tests.resources.ResourceTestUtil.createTestMonitor;
-import static org.junit.Assume.assumeTrue;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 import java.io.File;
 import java.io.IOException;
@@ -22,6 +22,7 @@
 import java.net.URI;
 import java.nio.file.Path;
 import org.eclipse.core.filesystem.URIUtil;
+import org.eclipse.core.internal.localstore.UnifiedTree;
 import org.eclipse.core.internal.resources.ProjectDescription;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IProjectDescription;
@@ -30,10 +31,11 @@
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.tests.resources.util.WorkspaceResetExtension;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestInfo;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
 /**
  * Tests for recursive symbolic links in projects.
@@ -47,7 +49,7 @@ public class Bug_185247_recursiveLinks {
 
 	@BeforeEach
 	public void requireCanCreateSymlinks(TestInfo testInfo) throws IOException {
-		assumeTrue("only relevant for platforms supporting symbolic links", canCreateSymLinks());
+		assumeTrue(canCreateSymLinks(), "only relevant for platforms supporting symbolic links");
 		testMethodName = testInfo.getTestMethod().get().getName();
 	}
 
@@ -62,13 +64,14 @@ public void requireCanCreateSymlinks(TestInfo testInfo) throws IOException {
 	 *         |-- link_current -> ./ (links "directory")
 	 * 
*/ - @Test - public void test1_linkCurrentDirectory() throws Exception { + @ParameterizedTest + @ValueSource(booleans = { false, true }) + public void test1_linkCurrentDirectory(boolean useAdvancedLinkCheck) throws Exception { CreateTestProjectStructure createSymlinks = directory -> { createSymlink(directory, "link_current", "./"); }; - runTest(createSymlinks); + runTest(createSymlinks, useAdvancedLinkCheck); } /** @@ -82,13 +85,14 @@ public void test1_linkCurrentDirectory() throws Exception { * |-- link_parent -> ../ (links "project root") * */ - @Test - public void test2_linkParentDirectory() throws Exception { + @ParameterizedTest + @ValueSource(booleans = { false, true }) + public void test2_linkParentDirectory(boolean useAdvancedLinkCheck) throws Exception { CreateTestProjectStructure createSymlinks = directory -> { createSymlink(directory, "link_parent", "../"); }; - runTest(createSymlinks); + runTest(createSymlinks, useAdvancedLinkCheck); } /** @@ -104,15 +108,16 @@ public void test2_linkParentDirectory() throws Exception { * |-- link_grandparent -> ../../ (links "project root") * */ - @Test - public void test3_linkGrandparentDirectory() throws Exception { + @ParameterizedTest + @ValueSource(booleans = { false, true }) + public void test3_linkGrandparentDirectory(boolean useAdvancedLinkCheck) throws Exception { CreateTestProjectStructure createSymlinks = directory -> { File subdirectory = new File(directory, "subdirectory"); createDirectory(subdirectory); createSymlink(subdirectory, "link_grandparent", "../../"); }; - runTest(createSymlinks); + runTest(createSymlinks, useAdvancedLinkCheck); } /** @@ -132,8 +137,9 @@ public void test3_linkGrandparentDirectory() throws Exception { * |-- link_parent -> ../ (links directory) * */ - @Test - public void test4_linkParentDirectoryTwice() throws Exception { + @ParameterizedTest + @ValueSource(booleans = { false, true }) + public void test4_linkParentDirectoryTwice(boolean useAdvancedLinkCheck) throws Exception { CreateTestProjectStructure createSymlinks = directory -> { String[] subdirectoryNames = { "subdirectory1", "subdirectory2" }; for (String subdirectoryName : subdirectoryNames) { @@ -143,7 +149,7 @@ public void test4_linkParentDirectoryTwice() throws Exception { } }; - runTest(createSymlinks); + runTest(createSymlinks, useAdvancedLinkCheck); } /** @@ -163,8 +169,9 @@ public void test4_linkParentDirectoryTwice() throws Exception { * |-- link_parent -> /tmp/<random string>/bug185247recursive/test5_linkParentDirectoyTwiceWithAbsolutePath/directory * */ - @Test - public void test5_linkParentDirectoyTwiceWithAbsolutePath() throws Exception { + @ParameterizedTest + @ValueSource(booleans = { false, true }) + public void test5_linkParentDirectoyTwiceWithAbsolutePath(boolean useAdvancedLinkCheck) throws Exception { CreateTestProjectStructure createSymlinks = directory -> { String[] subdirectoryNames = { "subdirectory1", "subdirectory2" }; for (String subdirectoryName : subdirectoryNames) { @@ -174,22 +181,28 @@ public void test5_linkParentDirectoyTwiceWithAbsolutePath() throws Exception { } }; - runTest(createSymlinks); + runTest(createSymlinks, useAdvancedLinkCheck); } - private void runTest(CreateTestProjectStructure createSymlinks) throws MalformedURLException, Exception { - String projectName = testMethodName; - IPath testRoot = IPath.fromPath(tempDirectory); - IPath projectRoot = testRoot.append("bug185247recursive").append(projectName); - File directory = projectRoot.append("directory").toFile(); - createDirectory(directory); - - createSymlinks.accept(directory); - - - URI projectRootLocation = URIUtil.toURI((projectRoot)); - // refreshing the project with recursive symlinks should not hang - importProjectAndRefresh(projectName, projectRootLocation); + private void runTest(CreateTestProjectStructure createSymlinks, boolean useAdvancedLinkCheck) + throws MalformedURLException, Exception { + final boolean originalValue = UnifiedTree.isAdvancedRecursiveLinkChecksEnabled(); + try { + UnifiedTree.enableAdvancedRecursiveLinkChecks(useAdvancedLinkCheck); + String projectName = testMethodName; + IPath testRoot = IPath.fromPath(tempDirectory); + IPath projectRoot = testRoot.append("bug185247recursive").append(projectName); + File directory = projectRoot.append("directory").toFile(); + createDirectory(directory); + + createSymlinks.accept(directory); + + URI projectRootLocation = URIUtil.toURI((projectRoot)); + // refreshing the project with recursive symlinks should not hang + importProjectAndRefresh(projectName, projectRootLocation); + } finally { + UnifiedTree.enableAdvancedRecursiveLinkChecks(originalValue); + } } private static void createDirectory(File directory) { diff --git a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/util/WorkspaceResetExtension.java b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/util/WorkspaceResetExtension.java index 937eeb73c1b..81af73f6faf 100644 --- a/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/util/WorkspaceResetExtension.java +++ b/resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/util/WorkspaceResetExtension.java @@ -40,7 +40,7 @@ public class WorkspaceResetExtension implements AfterEachCallback, BeforeEachCal public void beforeEach(ExtensionContext context) throws Exception { // Wait for any pending refresh operation, in particular from startup waitForRefresh(); - TestUtil.log(IStatus.INFO, context.getDisplayName(), "setUp"); + TestUtil.log(IStatus.INFO, getTestName(context), "setUp"); assertNotNull(getWorkspace(), "Workspace was not set up"); FreezeMonitor.expectCompletionInAMinute(); waitForRefresh(); @@ -48,7 +48,7 @@ public void beforeEach(ExtensionContext context) throws Exception { @Override public void afterEach(ExtensionContext context) throws Exception { - TestUtil.log(IStatus.INFO, context.getDisplayName(), "tearDown"); + TestUtil.log(IStatus.INFO, getTestName(context), "tearDown"); try { restoreCleanWorkspace(); } finally { @@ -57,6 +57,16 @@ public void afterEach(ExtensionContext context) throws Exception { } } + private String getTestName(ExtensionContext context) { + String className = context.getRequiredTestClass().getSimpleName(); + String methodName = context.getRequiredTestMethod().getName(); + String displayName = context.getDisplayName(); + if (!displayName.contains(methodName)) { + methodName += displayName; + } + return className + "." + methodName; + } + private void restoreCleanWorkspace() { List exceptions = new ArrayList<>(); try {