2727import org .eclipse .core .resources .IProject ;
2828import org .eclipse .core .resources .IProjectDescription ;
2929import org .eclipse .core .resources .IResource ;
30+ import org .eclipse .core .resources .IResourceVisitor ;
3031import org .eclipse .core .resources .ResourcesPlugin ;
3132import org .eclipse .core .runtime .IPath ;
3233import org .eclipse .core .tests .resources .util .WorkspaceResetExtension ;
@@ -184,7 +185,76 @@ public void test5_linkParentDirectoyTwiceWithAbsolutePath(boolean useAdvancedLin
184185 runTest (createSymlinks , useAdvancedLinkCheck );
185186 }
186187
187- private void runTest (CreateTestProjectStructure createSymlinks , boolean useAdvancedLinkCheck )
188+ /**
189+ * Test project structure:
190+ *
191+ * <pre>
192+ * project root
193+ * |-- directory
194+ * |
195+ * |- directory_1/
196+ * | |
197+ * | |- directory_1_1/
198+ * | |
199+ * | |- directory_1_1_1/
200+ * | |
201+ * | |- link_directory_2 -> ../../../directory_2/
202+ * |
203+ * |- directory_2/
204+ * |
205+ * |- directory_2_2/
206+ * |
207+ * |- link_directory_1 -> ../../directory_1/
208+ * </pre>
209+ */
210+ @ ParameterizedTest
211+ @ ValueSource (booleans = { false , true })
212+ public void test6_linkGrandparentTwice (boolean useAdvancedLinkCheck ) throws Exception {
213+ CreateTestProjectStructure createSymlinks = directory -> {
214+
215+ // directory_1/directory_1_1/directory_1_1_1/
216+ File directory1 = new File (directory , "directory_1" );
217+ File directory1_1 = new File (directory1 , "directory_1_1" );
218+ File directory1_1_1 = new File (directory1_1 , "directory_1_1_1" );
219+ createDirectory (directory1_1_1 );
220+
221+ // directory_2/directory_2_2/
222+ File directory2 = new File (directory , "directory_2" );
223+ File directory2_2 = new File (directory2 , "directory_2_2" );
224+ createDirectory (directory2_2 );
225+
226+ // link_directory_2 -> ../../../directory_2/ (from directory_1_1_1, goes up to
227+ // root directory)
228+ createSymlink (directory1_1_1 , "link_directory_2" , "../../../directory_2/" );
229+
230+ // link_directory_1 -> ../../directory_1/ (from directory_2_2, goes up to
231+ // root directory)
232+ createSymlink (directory2_2 , "link_directory_1" , "../../directory_1/" );
233+ };
234+
235+ IProject project = runTest (createSymlinks , useAdvancedLinkCheck );
236+ final boolean originalValue = UnifiedTree .isAdvancedRecursiveLinkChecksEnabled ();
237+ UnifiedTree .enableAdvancedRecursiveLinkChecks (useAdvancedLinkCheck );
238+ try {
239+ // visiting the project should not visit forever
240+ project .accept (new IResourceVisitor () {
241+ int resourceCount = 0 ;
242+
243+ @ Override
244+ public boolean visit (IResource resource ) {
245+ resourceCount ++;
246+ System .out .println (resourceCount + " visited: " + resource .getFullPath ());
247+ assertTrue (resourceCount <= 13 , "Expected max 13 elements to visit, got: " + resourceCount );
248+ return true ;
249+ }
250+ });
251+ } finally {
252+ UnifiedTree .enableAdvancedRecursiveLinkChecks (originalValue );
253+ }
254+
255+ }
256+
257+ private IProject runTest (CreateTestProjectStructure createSymlinks , boolean useAdvancedLinkCheck )
188258 throws MalformedURLException , Exception {
189259 final boolean originalValue = UnifiedTree .isAdvancedRecursiveLinkChecksEnabled ();
190260 try {
@@ -199,7 +269,8 @@ private void runTest(CreateTestProjectStructure createSymlinks, boolean useAdvan
199269
200270 URI projectRootLocation = URIUtil .toURI ((projectRoot ));
201271 // refreshing the project with recursive symlinks should not hang
202- importProjectAndRefresh (projectName , projectRootLocation );
272+ IProject project = importProjectAndRefresh (projectName , projectRootLocation );
273+ return project ;
203274 } finally {
204275 UnifiedTree .enableAdvancedRecursiveLinkChecks (originalValue );
205276 }
@@ -215,9 +286,10 @@ void createSymlink(File directory, String linkName, String linkTarget) throws IO
215286 createSymLink (directory , linkName , linkTarget , isDir );
216287 }
217288
218- private void importProjectAndRefresh (String projectName , URI projectRootLocation ) throws Exception {
289+ private IProject importProjectAndRefresh (String projectName , URI projectRootLocation ) throws Exception {
219290 IProject project = importTestProject (projectName , projectRootLocation );
220291 project .refreshLocal (IResource .DEPTH_INFINITE , createTestMonitor ());
292+ return project ;
221293 }
222294
223295 private IProject importTestProject (String projectName , URI projectRootLocation ) throws Exception {
0 commit comments