### Eclipse Workspace Patch 1.0 #P org.eclipse.core.tests.resources.2 Index: src/org/eclipse/core/tests/resources/LinkedResourceTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/LinkedResourceTest.java,v retrieving revision 1.50 diff -u -r1.50 LinkedResourceTest.java --- src/org/eclipse/core/tests/resources/LinkedResourceTest.java 1 Feb 2008 23:02:15 -0000 1.50 +++ src/org/eclipse/core/tests/resources/LinkedResourceTest.java 5 Dec 2008 10:19:34 -0000 @@ -11,6 +11,7 @@ package org.eclipse.core.tests.resources; import java.io.*; +import java.io.File; import java.net.URI; import java.util.HashMap; import junit.framework.Test; @@ -1615,4 +1616,136 @@ assertTrue("2.0", link.exists()); assertTrue("2.1", linkChild.exists()); } + + /** + * Bug251370 + * Updating a .project file within a nested Project causes problems when the project is closed + * and then reopened (having moved one of the linked resources) + * + * This test creates a linked resource between the inner project and outer project. + * The first linked resource is relative to a path variable "ROOT" + * The second is absolute. + * + * Overwrite the .project file externally. + */ + public void testChangingLinksWithNestedProjects() { + // /ExistingProject/foo + final String sOverlappingProject = "foo"; + final IFolder overlappingFolder = existingProject.getFolder(sOverlappingProject); + ensureExistsInFileSystem(overlappingFolder); + + // /foo -> /ExistingProject/foo + final IProject overlappingProject = getWorkspace().getRoot().getProject(sOverlappingProject); + IProjectDescription desc = getWorkspace().newProjectDescription(sOverlappingProject); + desc.setLocation(overlappingFolder.getLocation()); + try { + overlappingProject.create(desc, getMonitor()); + overlappingProject.open(getMonitor()); + assertTrue("0.9",overlappingProject.exists()); + } catch (CoreException e) { + fail("1.0"); + } + + // Create a path variable for the workspace root + try { + IPath ROOT = getWorkspace().getRoot().getLocation(); + getWorkspace().getPathVariableManager().setValue("ROOT", ROOT); + } catch (CoreException e) { + fail("1.5"); + } + + // Two linked resource paths: + // 1) Uses path variable + IPath l1 = new Path("ROOT").append(existingFolderInExistingProject.getFullPath()); + // 2) uses absolute path + IPath l2 = existingFolderInExistingProject.getLocation(); + + // Refresh Workspace + try { + getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); + } catch (CoreException e) { + fail ("2.0"); + } + + // Create a link to the folder in the existing project + // /foo/linkedFolder -> /ExistingProject/existingFolderInExistingProject + IFolder linkedFolder = overlappingProject.getFolder("linkedFolder"); + try { + linkedFolder.createLink(l1, IResource.REPLACE, getMonitor()); + assertTrue("1.9",linkedFolder.exists()); + // Copy the file to .project1 + overlappingProject.getFile(".project").copy(new Path(".project1"), true, getMonitor()); + } catch (CoreException e) { + fail("3.0"); + } + + // Change the variable to be relative to the ROOT variable + try { + linkedFolder.delete(true, getMonitor()); + linkedFolder.createLink(l2, IResource.REPLACE, getMonitor()); + assertTrue(linkedFolder.exists()); + // Copy the file to .project2 + overlappingProject.getFile(".project").copy(new Path(".project2"), true, getMonitor()); + } catch (CoreException e) { + fail("5.0"); + } + + try { + overlappingProject.close(getMonitor()); + copyFile(overlappingFolder.getFile(".project1").getLocation().toFile(), + overlappingFolder.getFile(".project").getLocation().toFile()); + overlappingProject.open(getMonitor()); + getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); + } catch (CoreException e) { + fail ("10.0"); + } + + try { + copyFile(overlappingFolder.getFile(".project2").getLocation().toFile(), + overlappingFolder.getFile(".project").getLocation().toFile()); + overlappingProject.open(getMonitor()); + getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); + } catch (CoreException e) { + fail ("11.0"); + } + } + + /** + * Helper method to copy file from source to dest, ensuring that the modification + * time has incremented + * @param src + * @param dst + */ + private void copyFile(File src, File dst) { + long initModificationTime = dst.lastModified(); + FileInputStream in = null; + FileOutputStream out = null; + try { + in = new FileInputStream(src); + out = new FileOutputStream(dst); + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = in.read(buffer)) != -1) + out.write(buffer, 0, bytesRead); + } catch (Exception e) { + fail("Exception copyingFile: " + src.getAbsolutePath() + " -> " + dst.getAbsolutePath()); + } finally { + if (in != null) + try {in.close();} catch (Exception e) {/*Don't care*/} + if (out != null) + try {out.close();} catch (Exception e) {/*Don't care*/} + } + + while (dst.lastModified() - initModificationTime == 0) { + // Unix stat doesn't return granularity < 1000ms :( + // If we don't sleep here, and the unit test goes too quickly, we're scuppered. + try { + Thread.sleep(200); + } catch (InterruptedException e) { + // Don't care + } + dst.setLastModified(System.currentTimeMillis()); + } + } + }