/******************************************************************************* * Copyright (c) 2000, 2017 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Sergey Prigogin (Google) - [338010] Resource.createLink() does not preserve symbolic links *******************************************************************************/ 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; import junit.framework.TestSuite; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.filesystem.URIUtil; import org.eclipse.core.internal.resources.*; import org.eclipse.core.internal.utils.FileUtil; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.core.tests.harness.CancelingProgressMonitor; import org.eclipse.core.tests.harness.FussyProgressMonitor; /** * Tests the following API methods: * IFile#createLink * IFolder#createLink * * This test supports both variable-based and non-variable-based locations. * Although the method used for creating random locations * <code>ResourceTest#getRandomLocation()</code> never returns variable- * based paths, this method is overwritten in the derived class * <code>LinkedResourceWithPathVariable</code> to always return variable-based * paths. * * To support variable-based paths wherever a file system location is used, it * is mandatory first to resolve it and only then using it, except in calls to * <code>IFile#createLink</code> and <code>IFolder#createLink</code> and when * the location is obtained using <code>IResource#getLocation()</code>. */ public class LinkedResourceTest extends ResourceTest { protected String childName = "File.txt"; protected IProject closedProject; protected IFile existingFileInExistingProject; protected IFolder existingFolderInExistingFolder; protected IFolder existingFolderInExistingProject; protected IProject existingProject; protected IProject existingProjectInSubDirectory; protected IPath localFile; protected IPath localFolder; protected IFile nonExistingFileInExistingFolder; protected IFile nonExistingFileInExistingProject; protected IFile nonExistingFileInOtherExistingProject; protected IFolder nonExistingFolderInExistingFolder; protected IFolder nonExistingFolderInExistingProject; protected IFolder nonExistingFolderInNonExistingFolder; protected IFolder nonExistingFolderInNonExistingProject; protected IFolder nonExistingFolderInOtherExistingProject; protected IPath nonExistingLocation; protected IProject nonExistingProject; protected IProject otherExistingProject; public static Test suite() { return new TestSuite(LinkedResourceTest.class); // TestSuite suite = new TestSuite(); // suite.addTest(new LinkedResourceTest("testFindFilesForLocationCaseVariant")); // return suite; } public LinkedResourceTest() { super(); } public LinkedResourceTest(String name) { super(name); } protected void doCleanup() throws Exception { ensureExistsInWorkspace(new IResource[] {existingProject, otherExistingProject, closedProject, existingFolderInExistingProject, existingFolderInExistingFolder, existingFileInExistingProject}, true); closedProject.close(getMonitor()); ensureDoesNotExistInWorkspace(new IResource[] {nonExistingProject, nonExistingFolderInExistingProject, nonExistingFolderInExistingFolder, nonExistingFolderInOtherExistingProject, nonExistingFolderInNonExistingProject, nonExistingFolderInNonExistingFolder, nonExistingFileInExistingProject, nonExistingFileInOtherExistingProject, nonExistingFileInExistingFolder}); ensureDoesNotExistInFileSystem(resolve(nonExistingLocation).toFile()); resolve(localFolder).toFile().mkdirs(); createFileInFileSystem(resolve(localFile), getRandomContents()); } private byte[] getFileContents(IFile file) throws CoreException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); transferData(new BufferedInputStream(file.getContents()), bout); return bout.toByteArray(); } /** * Maybe overridden in subclasses that use path variables. */ protected IPath resolve(IPath path) { return path; } /** * Maybe overridden in subclasses that use path variables. */ protected URI resolve(URI uri) { return uri; } @Override protected void setUp() throws Exception { super.setUp(); existingProject = getWorkspace().getRoot().getProject("ExistingProject"); existingProjectInSubDirectory = getWorkspace().getRoot().getProject("ExistingProjectInSubDirectory"); otherExistingProject = getWorkspace().getRoot().getProject("OtherExistingProject"); closedProject = getWorkspace().getRoot().getProject("ClosedProject"); existingFolderInExistingProject = existingProject.getFolder("existingFolderInExistingProject"); existingFolderInExistingFolder = existingFolderInExistingProject.getFolder("existingFolderInExistingFolder"); nonExistingFolderInExistingProject = existingProject.getFolder("nonExistingFolderInExistingProject"); nonExistingFolderInOtherExistingProject = otherExistingProject.getFolder("nonExistingFolderInOtherExistingProject"); nonExistingFolderInNonExistingFolder = nonExistingFolderInExistingProject.getFolder("nonExistingFolderInNonExistingFolder"); nonExistingFolderInExistingFolder = existingFolderInExistingProject.getFolder("nonExistingFolderInExistingFolder"); nonExistingProject = getWorkspace().getRoot().getProject("NonProject"); nonExistingFolderInNonExistingProject = nonExistingProject.getFolder("nonExistingFolderInNonExistingProject"); existingFileInExistingProject = existingProject.getFile("existingFileInExistingProject"); nonExistingFileInExistingProject = existingProject.getFile("nonExistingFileInExistingProject"); nonExistingFileInOtherExistingProject = otherExistingProject.getFile("nonExistingFileInOtherExistingProject"); nonExistingFileInExistingFolder = existingFolderInExistingProject.getFile("nonExistingFileInExistingFolder"); localFolder = getRandomLocation(); nonExistingLocation = getRandomLocation(); localFile = localFolder.append(childName); doCleanup(); if (!existingProjectInSubDirectory.exists()) { IProjectDescription desc = getWorkspace().newProjectDescription(existingProjectInSubDirectory.getName()); File dir = existingProject.getLocation().toFile(); dir = dir.getParentFile(); dir = new File(dir + File.separator + "sub" + File.separator + "dir" + File.separator + "more" + File.separator + "proj"); dir.mkdirs(); desc.setLocation(Path.fromOSString(dir.getAbsolutePath())); existingProjectInSubDirectory.create(desc, getMonitor()); } if (!existingProjectInSubDirectory.isOpen()) { existingProjectInSubDirectory.open(getMonitor()); } } @Override protected void tearDown() throws Exception { super.tearDown(); Workspace.clear(resolve(localFolder).toFile()); Workspace.clear(resolve(nonExistingLocation).toFile()); } /** * Tests creation of a linked resource whose corresponding file system * path does not exist. This should succeed but no operations will be * available on the resulting resource. */ public void testAllowMissingLocal() { //get a non-existing location IPath location = getRandomLocation(); IFolder folder = nonExistingFolderInExistingProject; //try to create without the flag (should fail) try { folder.createLink(location, IResource.NONE, getMonitor()); fail("1.0"); } catch (CoreException e) { //should fail } //now try to create with the flag (should succeed) try { folder.createLink(location, IResource.ALLOW_MISSING_LOCAL, getMonitor()); } catch (CoreException e) { fail("1.1", e); } assertEquals("1.2", resolve(location), folder.getLocation()); assertTrue("1.3", !resolve(location).toFile().exists()); //getting children should succeed (and be empty) try { assertEquals("1.4", 0, folder.members().length); } catch (CoreException e) { fail("1.5", e); } //delete should succeed try { folder.delete(IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.6", e); } //try to create with local path that can never exist if (isWindows()) { location = new Path("b:\\does\\not\\exist"); } else { location = new Path("/dev/null/does/not/exist"); } location = FileUtil.canonicalPath(location); try { folder.createLink(location, IResource.NONE, getMonitor()); fail("2.1"); } catch (CoreException e) { //should fail } try { folder.createLink(location, IResource.ALLOW_MISSING_LOCAL, getMonitor()); } catch (CoreException e) { fail("2.2", e); } assertEquals("2.3", location, folder.getLocation()); assertTrue("2.4", !location.toFile().exists()); // creating child should fail try { folder.getFile("abc.txt").create(getRandomContents(), IResource.NONE, getMonitor()); fail("2.5"); } catch (CoreException e) { //should fail } } /** * Tests case where a resource in the file system cannot be added to the workspace * because it is blocked by a linked resource of the same name. */ public void testBlockedFolder() { //create local folder that will be blocked ensureExistsInFileSystem(nonExistingFolderInExistingProject); IFile blockedFile = nonExistingFolderInExistingProject.getFile("BlockedFile"); createFileInFileSystem(blockedFile.getLocation(), getRandomContents()); try { //link the folder elsewhere nonExistingFolderInExistingProject.createLink(localFolder, IResource.NONE, getMonitor()); //refresh the project existingProject.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); } catch (CoreException e) { fail("1.1", e); } //the blocked file should not exist in the workspace assertTrue("1.2", !blockedFile.exists()); assertTrue("1.3", nonExistingFolderInExistingProject.exists()); assertTrue("1.4", nonExistingFolderInExistingProject.getFile(childName).exists()); assertEquals("1.5", nonExistingFolderInExistingProject.getLocation(), resolve(localFolder)); //now delete the link try { nonExistingFolderInExistingProject.delete(IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.99", e); } //the blocked file and the linked folder should not exist in the workspace assertTrue("2.0", !blockedFile.exists()); assertTrue("2.1", !nonExistingFolderInExistingProject.exists()); assertTrue("2.2", !nonExistingFolderInExistingProject.getFile(childName).exists()); assertEquals("2.3", nonExistingFolderInExistingProject.getLocation(), existingProject.getLocation().append(nonExistingFolderInExistingProject.getName())); //now refresh again to discover the blocked resource try { existingProject.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); } catch (CoreException e) { fail("2.99", e); } //the blocked file should now exist assertTrue("3.0", blockedFile.exists()); assertTrue("3.1", nonExistingFolderInExistingProject.exists()); assertTrue("3.2", !nonExistingFolderInExistingProject.getFile(childName).exists()); assertEquals("3.3", nonExistingFolderInExistingProject.getLocation(), existingProject.getLocation().append(nonExistingFolderInExistingProject.getName())); //attempting to link again will fail because the folder exists in the workspace try { nonExistingFolderInExistingProject.createLink(localFolder, IResource.NONE, getMonitor()); fail("3.4"); } catch (CoreException e) { //expected } } /** * This test creates a linked folder resource, then changes the directory in * the file system to be a file. On refresh, the linked resource should * still exist, should have the correct gender, and still be a linked * resource. */ public void testChangeLinkGender() { IFolder folder = nonExistingFolderInExistingProject; IFile file = folder.getProject().getFile(folder.getProjectRelativePath()); IPath resolvedLocation = resolve(localFolder); try { folder.createLink(localFolder, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("0.99", e); } ensureDoesNotExistInFileSystem(resolvedLocation.toFile()); createFileInFileSystem(resolvedLocation, getRandomContents()); try { folder.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); } catch (CoreException e) { fail("2.99", e); } assertTrue("3.0", !folder.exists()); assertTrue("3.1", file.exists()); assertTrue("3.2", file.isLinked()); assertEquals("3.3", resolvedLocation, file.getLocation()); //change back to folder ensureDoesNotExistInFileSystem(resolvedLocation.toFile()); resolvedLocation.toFile().mkdirs(); try { folder.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); } catch (CoreException e) { fail("3.99", e); } assertTrue("4.0", folder.exists()); assertTrue("4.1", !file.exists()); assertTrue("4.2", folder.isLinked()); assertEquals("4.3", resolvedLocation, folder.getLocation()); } public void testCopyFile() { IResource[] sources = new IResource[] {nonExistingFileInExistingProject, nonExistingFileInExistingFolder}; IResource[] destinationResources = new IResource[] {existingProject, closedProject, nonExistingFileInOtherExistingProject, nonExistingFileInExistingFolder}; Boolean[] deepCopy = new Boolean[] {Boolean.TRUE, Boolean.FALSE}; IProgressMonitor[] monitors = new IProgressMonitor[] {new FussyProgressMonitor(), new CancelingProgressMonitor(), null}; Object[][] inputs = new Object[][] {sources, destinationResources, deepCopy, monitors}; new TestPerformer("LinkedResourceTest.testCopyFile") { protected static final String CANCELED = "canceled"; @Override public void cleanUp(Object[] args, int count) { super.cleanUp(args, count); try { doCleanup(); } catch (Exception e) { fail("invocation " + count + " failed to cleanup", e); } } @Override public Object invokeMethod(Object[] args, int count) throws Exception { IFile source = (IFile) args[0]; IResource destination = (IResource) args[1]; boolean isDeep = ((Boolean) args[2]).booleanValue(); IProgressMonitor monitor = (IProgressMonitor) args[3]; if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).prepare(); } try { source.createLink(localFile, IResource.NONE, null); source.copy(destination.getFullPath(), isDeep ? IResource.NONE : IResource.SHALLOW, monitor); } catch (OperationCanceledException e) { return CANCELED; } if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).sanityCheck(); } return null; } @Override public boolean shouldFail(Object[] args, int count) { IFile source = (IFile) args[0]; IResource destination = (IResource) args[1]; boolean isDeep = ((Boolean) args[2]).booleanValue(); IProgressMonitor monitor = (IProgressMonitor) args[3]; if (monitor instanceof CancelingProgressMonitor) { return false; } if (source.equals(destination)) { return true; } IResource parent = destination.getParent(); if (!isDeep && parent == null) { return true; } if (!parent.isAccessible()) { return true; } if (destination.exists()) { return true; } //passed all failure cases so it should succeed return false; } @Override public boolean wasSuccess(Object[] args, Object result, Object[] oldState) throws Exception { IFile source = (IFile) args[0]; IResource destination = (IResource) args[1]; boolean isDeep = ((Boolean) args[2]).booleanValue(); IProgressMonitor monitor = (IProgressMonitor) args[3]; if (result == CANCELED) { return monitor instanceof CancelingProgressMonitor; } if (!destination.exists()) { return false; } //destination should only be linked for a shallow copy if (isDeep) { if (destination.isLinked()) { return false; } if (source.getLocation().equals(destination.getLocation())) { return false; } if (!destination.getProject().getLocation().isPrefixOf(destination.getLocation())) { return false; } } else { if (!destination.isLinked()) { return false; } if (!source.getLocation().equals(destination.getLocation())) { return false; } if (!source.getRawLocation().equals(destination.getRawLocation())) { return false; } if (!source.getLocationURI().equals(destination.getLocationURI())) { return false; } } return true; } }.performTest(inputs); } public void testCopyFolder() { IFolder[] sources = new IFolder[] {nonExistingFolderInExistingProject, nonExistingFolderInExistingFolder}; IResource[] destinations = new IResource[] {existingProject, closedProject, nonExistingProject, existingFolderInExistingProject, nonExistingFolderInOtherExistingProject, nonExistingFolderInExistingFolder}; Boolean[] deepCopy = new Boolean[] {Boolean.TRUE, Boolean.FALSE}; IProgressMonitor[] monitors = new IProgressMonitor[] {new FussyProgressMonitor(), new CancelingProgressMonitor(), null}; Object[][] inputs = new Object[][] {sources, destinations, deepCopy, monitors}; new TestPerformer("LinkedResourceTest.testCopyFolder") { protected static final String CANCELED = "canceled"; @Override public void cleanUp(Object[] args, int count) { super.cleanUp(args, count); try { doCleanup(); } catch (Exception e) { fail("invocation " + count + " failed to cleanup", e); } } @Override public Object invokeMethod(Object[] args, int count) throws Exception { IFolder source = (IFolder) args[0]; IResource destination = (IResource) args[1]; boolean isDeep = ((Boolean) args[2]).booleanValue(); IProgressMonitor monitor = (IProgressMonitor) args[3]; if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).prepare(); } try { source.createLink(localFolder, IResource.NONE, null); source.copy(destination.getFullPath(), isDeep ? IResource.NONE : IResource.SHALLOW, monitor); } catch (OperationCanceledException e) { return CANCELED; } if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).sanityCheck(); } return null; } @Override public boolean shouldFail(Object[] args, int count) { IFolder source = (IFolder) args[0]; IResource destination = (IResource) args[1]; boolean isDeep = ((Boolean) args[2]).booleanValue(); IProgressMonitor monitor = (IProgressMonitor) args[3]; if (monitor instanceof CancelingProgressMonitor) { return false; } IResource parent = destination.getParent(); if (destination.getType() == IResource.PROJECT) { return true; } if (source.equals(destination)) { return true; } if (!isDeep && parent == null) { return true; } if (!parent.isAccessible()) { return true; } if (destination.exists()) { return true; } //passed all failure case so it should succeed return false; } @Override public boolean wasSuccess(Object[] args, Object result, Object[] oldState) throws Exception { IFolder source = (IFolder) args[0]; IResource destination = (IResource) args[1]; boolean isDeep = ((Boolean) args[2]).booleanValue(); IProgressMonitor monitor = (IProgressMonitor) args[3]; if (result == CANCELED) { return monitor instanceof CancelingProgressMonitor; } if (!destination.exists()) { return false; } //destination should only be linked for a shallow copy if (isDeep) { if (destination.isLinked()) { return false; } if (source.getLocation().equals(destination.getLocation())) { return false; } if (!destination.getProject().getLocation().isPrefixOf(destination.getLocation())) { return false; } } else { if (!destination.isLinked()) { return false; } if (!source.getLocation().equals(destination.getLocation())) { return false; } if (!source.getLocationURI().equals(destination.getLocationURI())) { return false; } if (!source.getRawLocation().equals(destination.getRawLocation())) { return false; } } return true; } }.performTest(inputs); } /** * Tests copying a linked file resource that doesn't exist in the file system */ public void testCopyMissingFile() { IPath location = getRandomLocation(); IFile linkedFile = nonExistingFileInExistingProject; try { linkedFile.createLink(location, IResource.ALLOW_MISSING_LOCAL, getMonitor()); } catch (CoreException e) { fail("1.99", e); } IFile dest = existingProject.getFile("FailedCopyDest"); try { linkedFile.copy(dest.getFullPath(), IResource.NONE, getMonitor()); fail("2.0"); } catch (CoreException e1) { //should fail } assertTrue("2.1", !dest.exists()); try { linkedFile.copy(dest.getFullPath(), IResource.FORCE, getMonitor()); fail("2.2"); } catch (CoreException e1) { //should fail } assertTrue("2.3", !dest.exists()); } /** * Tests copying a linked folder that doesn't exist in the file system */ public void testCopyMissingFolder() { IPath location = getRandomLocation(); IFolder linkedFolder = nonExistingFolderInExistingProject; try { linkedFolder.createLink(location, IResource.ALLOW_MISSING_LOCAL, getMonitor()); } catch (CoreException e) { fail("1.99", e); } IFolder dest = existingProject.getFolder("FailedCopyDest"); try { linkedFolder.copy(dest.getFullPath(), IResource.NONE, getMonitor()); fail("2.0"); } catch (CoreException e1) { //should fail } assertTrue("2.1", !dest.exists()); try { linkedFolder.copy(dest.getFullPath(), IResource.FORCE, getMonitor()); fail("2.2"); } catch (CoreException e1) { //should fail } assertTrue("2.3", !dest.exists()); } public void testCopyProjectWithLinks() { IPath fileLocation = getRandomLocation(); IFile linkedFile = nonExistingFileInExistingProject; IFolder linkedFolder = nonExistingFolderInExistingProject; try { try { createFileInFileSystem(resolve(fileLocation), getRandomContents()); linkedFolder.createLink(localFolder, IResource.NONE, getMonitor()); linkedFile.createLink(fileLocation, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.0", e); } //copy the project IProject destination = getWorkspace().getRoot().getProject("CopyTargetProject"); try { existingProject.copy(destination.getFullPath(), IResource.SHALLOW, getMonitor()); } catch (CoreException e) { fail("2.0", e); } IFile newFile = destination.getFile(linkedFile.getProjectRelativePath()); assertTrue("3.0", newFile.isLinked()); assertEquals("3.1", linkedFile.getLocation(), newFile.getLocation()); IFolder newFolder = destination.getFolder(linkedFolder.getProjectRelativePath()); assertTrue("4.0", newFolder.isLinked()); assertEquals("4.1", linkedFolder.getLocation(), newFolder.getLocation()); //test project deep copy try { destination.delete(IResource.NONE, getMonitor()); existingProject.copy(destination.getFullPath(), IResource.NONE, getMonitor()); } catch (CoreException e) { fail("5.0", e); } assertTrue("5.1", !newFile.isLinked()); assertEquals("5.2", destination.getLocation().append(newFile.getProjectRelativePath()), newFile.getLocation()); assertTrue("5.3", !newFolder.isLinked()); assertEquals("5.4", destination.getLocation().append(newFolder.getProjectRelativePath()), newFolder.getLocation()); //test copy project when linked resources don't exist with force=false try { destination.delete(IResource.NONE, getMonitor()); } catch (CoreException e) { fail("5.99", e); } assertTrue("6.0", resolve(fileLocation).toFile().delete()); try { existingProject.copy(destination.getFullPath(), IResource.NONE, getMonitor()); fail("6.1"); } catch (CoreException e) { //should fail } //all members except the missing link should have been copied assertTrue("6.2", destination.exists()); assertTrue("6.2.1", !destination.getFile(linkedFile.getName()).exists()); try { IResource[] srcChildren = existingProject.members(); for (int i = 0; i < srcChildren.length; i++) { if (!srcChildren[i].equals(linkedFile)) { assertNotNull("6.3." + i, destination.findMember(srcChildren[i].getProjectRelativePath())); } } } catch (CoreException e) { fail("6.4", e); } //test copy project when linked resources don't exist with force=true //this should mostly succeed, but still throw an exception indicating //a resource could not be copied because its location was missing try { destination.delete(IResource.NONE, getMonitor()); } catch (CoreException e) { fail("6.5", e); } try { existingProject.copy(destination.getFullPath(), IResource.FORCE, getMonitor()); fail("6.6"); } catch (CoreException e) { //should fail } assertTrue("6.7", destination.exists()); assertTrue("6.7.1", !destination.getFile(linkedFile.getName()).exists()); //all members except the missing link should have been copied try { IResource[] srcChildren = existingProject.members(); for (int i = 0; i < srcChildren.length; i++) { if (!srcChildren[i].equals(linkedFile)) { assertNotNull("6.8." + i, destination.findMember(srcChildren[i].getProjectRelativePath())); } } } catch (CoreException e) { fail("6.99", e); } } finally { Workspace.clear(resolve(fileLocation).toFile()); } } /** * Tests creating a linked folder and performing refresh in the background */ public void testCreateFolderInBackground() throws CoreException { final IFileStore rootStore = getTempStore(); rootStore.mkdir(IResource.NONE, getMonitor()); IFileStore childStore = rootStore.getChild("file.txt"); createFileInFileSystem(childStore); IFolder link = nonExistingFolderInExistingProject; link.createLink(rootStore.toURI(), IResource.BACKGROUND_REFRESH, getMonitor()); waitForRefresh(); IFile linkChild = link.getFile(childStore.getName()); assertTrue("1.0", link.exists()); assertTrue("1.1", link.isSynchronized(IResource.DEPTH_INFINITE)); assertTrue("1.2", linkChild.exists()); assertTrue("1.3", linkChild.isSynchronized(IResource.DEPTH_INFINITE)); } /** * Tests creating a linked resource with the same name but different * case as an existing resource. On case insensitive platforms this should fail. */ public void testCreateLinkCaseVariant() { IFolder link = nonExistingFolderInExistingProject; IFolder variant = link.getParent().getFolder(new Path(link.getName().toUpperCase())); ensureExistsInWorkspace(variant, true); try { link.createLink(localFolder, IResource.NONE, getMonitor()); //should fail on case insensitive platforms if (!isCaseSensitive(variant)) { fail("1.0"); } } catch (CoreException e) { //should not fail on case sensitive platforms if (isCaseSensitive(variant)) { fail("1.1", e); } } } /** * Tests creating a linked resource by modifying the .project file directly. * This is a regression test for bug 63331. */ public void testCreateLinkInDotProject() { final IFile dotProject = existingProject.getFile(IProjectDescription.DESCRIPTION_FILE_NAME); IFile link = nonExistingFileInExistingProject; byte[] oldContents = null; try { //create a linked file link.createLink(localFile, IResource.NONE, getMonitor()); //copy the .project file contents oldContents = getFileContents(dotProject); //delete linked file link.delete(IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.99", e); } final byte[] finalContents = oldContents; try { //recreate the link in a workspace runnable with create scheduling rule getWorkspace().run((IWorkspaceRunnable) monitor -> dotProject.setContents(new ByteArrayInputStream(finalContents), IResource.NONE, getMonitor()), getWorkspace().getRuleFactory().modifyRule(dotProject), IResource.NONE, getMonitor()); } catch (CoreException e1) { fail("2.99", e1); } } /** * Tests creating a project whose .project file already defines links at * depth greater than one. See bug 121322. */ public void testCreateProjectWithDeepLinks() { IProject project = existingProject; IFolder parent = existingFolderInExistingProject; IFolder folder = nonExistingFolderInExistingFolder; try { folder.createLink(localFolder, IResource.NONE, getMonitor()); //delete and recreate the project project.delete(IResource.NEVER_DELETE_PROJECT_CONTENT, getMonitor()); project.create(getMonitor()); project.open(IResource.BACKGROUND_REFRESH, getMonitor()); assertTrue("1.0", folder.exists()); assertTrue("1.1", parent.exists()); assertTrue("1.2", parent.isLocal(IResource.DEPTH_INFINITE)); } catch (CoreException e) { fail("1.99", e); } } /** * Tests whether {@link IFile#createLink} and {@link IFolder#createLink} * handle {@link IResource#HIDDEN} flag properly. */ public void testCreateHiddenLinkedResources() { IFolder folder = existingProject.getFolder("folder"); IFile file = existingProject.getFile("file.txt"); try { folder.createLink(localFolder, IResource.HIDDEN, getMonitor()); } catch (CoreException e) { fail("1.0", e); } try { file.createLink(localFile, IResource.HIDDEN, getMonitor()); } catch (CoreException e) { fail("2.0", e); } assertTrue("3.0", folder.isHidden()); assertTrue("4.0", file.isHidden()); } public void testDeepMoveProjectWithLinks() { IPath fileLocation = getRandomLocation(); IFile file = nonExistingFileInExistingProject; IFolder folder = nonExistingFolderInExistingProject; IFile childFile = folder.getFile(childName); IResource[] oldResources = new IResource[] {file, folder, existingProject, childFile}; try { try { createFileInFileSystem(resolve(fileLocation)); folder.createLink(localFolder, IResource.NONE, getMonitor()); file.createLink(fileLocation, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.0", e); } //move the project IProject destination = getWorkspace().getRoot().getProject("MoveTargetProject"); IFile newFile = destination.getFile(file.getProjectRelativePath()); IFolder newFolder = destination.getFolder(folder.getProjectRelativePath()); IFile newChildFile = newFolder.getFile(childName); IResource[] newResources = new IResource[] {destination, newFile, newFolder, newChildFile}; assertDoesNotExistInWorkspace("2.0", destination); try { existingProject.move(destination.getFullPath(), IResource.NONE, getMonitor()); } catch (CoreException e) { fail("2.1", e); } assertExistsInWorkspace("3.0", newResources); assertDoesNotExistInWorkspace("3.1", oldResources); assertTrue("3.2", existingProject.isSynchronized(IResource.DEPTH_INFINITE)); assertTrue("3.3", destination.isSynchronized(IResource.DEPTH_INFINITE)); assertTrue("3.4", !newFile.isLinked()); assertEquals("3.5", destination.getLocation().append(newFile.getProjectRelativePath()), newFile.getLocation()); assertTrue("3.6", !newFolder.isLinked()); assertEquals("3.7", destination.getLocation().append(newFolder.getProjectRelativePath()), newFolder.getLocation()); assertTrue("3.8", destination.isSynchronized(IResource.DEPTH_INFINITE)); } finally { Workspace.clear(resolve(fileLocation).toFile()); } } /** * Tests deleting the parent of a linked resource. */ public void testDeleteLinkParent() { IFolder link = nonExistingFolderInExistingFolder; IFolder linkParent = existingFolderInExistingProject; IFile linkChild = link.getFile("child.txt"); IFileStore childStore = null; try { link.createLink(localFolder, IResource.NONE, getMonitor()); ensureExistsInWorkspace(linkChild, true); childStore = EFS.getStore(linkChild.getLocationURI()); } catch (CoreException e) { fail("0.99", e); } //everything should exist at this point assertTrue("1.0", linkParent.exists()); assertTrue("1.1", link.exists()); assertTrue("1.2", linkChild.exists()); //delete the parent of the link try { linkParent.delete(IResource.KEEP_HISTORY, getMonitor()); } catch (CoreException e) { fail("1.99", e); } //resources should not exist, but link content should exist on disk assertTrue("2.0", !linkParent.exists()); assertTrue("2.1", !link.exists()); assertTrue("2.2", !linkChild.exists()); assertTrue("2.3", childStore.fetchInfo().exists()); } /** * Tests deleting and then recreating a project */ public void testDeleteProjectWithLinks() { IFolder link = nonExistingFolderInExistingProject; try { link.createLink(localFolder, IResource.NONE, getMonitor()); existingProject.delete(IResource.NEVER_DELETE_PROJECT_CONTENT, getMonitor()); existingProject.create(getMonitor()); } catch (CoreException e) { fail("0.99", e); } //link should not exist until the project is open assertTrue("1.0", !link.exists()); try { existingProject.open(getMonitor()); } catch (CoreException e) { fail("1.99", e); } //link should now exist assertTrue("2.0", link.exists()); assertTrue("2.1", link.isLinked()); assertEquals("2.2", resolve(localFolder), link.getLocation()); } /** * Tests deleting a linked resource when .project is read-only */ public void testDeleteLink_Bug351823() throws CoreException { IProject project = existingProject; IFile link = project.getFile(getUniqueString()); link.createLink(localFile, IResource.NONE, getMonitor()); // set .project read-only IFile descriptionFile = project.getFile(IProjectDescription.DESCRIPTION_FILE_NAME); ResourceAttributes attrs = descriptionFile.getResourceAttributes(); attrs.setReadOnly(true); descriptionFile.setResourceAttributes(attrs); try { try { link.delete(false, getMonitor()); fail("1.0"); } catch (CoreException e1) { // should fail } assertTrue("2.0", link.exists()); assertTrue("3.0", link.isLinked()); HashMap<IPath, LinkDescription> links = ((Project) project).internalGetDescription().getLinks(); assertNotNull("4.0", links); assertEquals("5.0", 1, links.size()); LinkDescription linkDesc = links.values().iterator().next(); assertEquals("6.0", link.getProjectRelativePath(), linkDesc.getProjectRelativePath()); // try to delete again // if the project description in memory is ok, it should fail try { link.delete(false, getMonitor()); fail("7.0"); } catch (CoreException e1) { // should fail } } finally { // set .project writable attrs = descriptionFile.getResourceAttributes(); attrs.setReadOnly(false); descriptionFile.setResourceAttributes(attrs); } } /** * Tests bug 209175. */ public void testDeleteFolderWithLinks() { IProject project = existingProject; IFolder folder = existingFolderInExistingProject; IFile file1 = folder.getFile(getUniqueString()); IFile file2 = project.getFile(getUniqueString()); try { file1.createLink(localFile, IResource.NONE, getMonitor()); file2.createLink(localFile, IResource.NONE, getMonitor()); HashMap<IPath, LinkDescription> links = ((Project) project).internalGetDescription().getLinks(); LinkDescription linkDescription1 = links.get(file1.getProjectRelativePath()); assertNotNull("1.0", linkDescription1); assertEquals("1.1", URIUtil.toURI(localFile), linkDescription1.getLocationURI()); LinkDescription linkDescription2 = links.get(file2.getProjectRelativePath()); assertNotNull("2.0", linkDescription2); assertEquals("2.1", URIUtil.toURI(localFile), linkDescription2.getLocationURI()); folder.delete(true, getMonitor()); links = ((Project) project).internalGetDescription().getLinks(); linkDescription1 = links.get(file1.getProjectRelativePath()); assertNull("3.0", linkDescription1); linkDescription2 = links.get(file2.getProjectRelativePath()); assertNotNull("4.0", linkDescription2); assertEquals("4.1", URIUtil.toURI(localFile), linkDescription2.getLocationURI()); } catch (CoreException e) { fail("5.0", e); } } /** * Tests that IWorkspaceRoot.findFilesForLocation works correctly * in presence of a linked resource that does not match the case in the file system */ public void testFindFilesForLocationCaseVariant() { //this test only applies to file systems with a device in the path if (!isWindows()) { return; } IFolder link = nonExistingFolderInExistingProject; IPath localLocation = resolve(localFolder); IPath upperCase = localLocation.setDevice(localLocation.getDevice().toUpperCase()); IPath lowerCase = localLocation.setDevice(localLocation.getDevice().toLowerCase()); try { link.createLink(upperCase, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.99", e); } IPath lowerCaseFilePath = lowerCase.append("file.txt"); IFile[] files = getWorkspace().getRoot().findFilesForLocation(lowerCaseFilePath); assertEquals("1.0", 1, files.length); } /** * Tests the {@link org.eclipse.core.resources.IResource#isLinked(int)} method. */ public void testIsLinked() { //initially nothing is linked IResource[] toTest = new IResource[] {closedProject, existingFileInExistingProject, existingFolderInExistingFolder, existingFolderInExistingProject, existingProject, nonExistingFileInExistingFolder, nonExistingFileInExistingProject, nonExistingFileInOtherExistingProject, nonExistingFolderInExistingFolder, nonExistingFolderInExistingProject, nonExistingFolderInNonExistingFolder, nonExistingFolderInNonExistingProject, nonExistingFolderInOtherExistingProject, nonExistingProject, otherExistingProject}; for (int i = 0; i < toTest.length; i++) { assertTrue("1.0 " + toTest[i], !toTest[i].isLinked()); assertTrue("1.1 " + toTest[i], !toTest[i].isLinked(IResource.NONE)); assertTrue("1.2 " + toTest[i], !toTest[i].isLinked(IResource.CHECK_ANCESTORS)); } // create a link IFolder link = nonExistingFolderInExistingProject; try { link.createLink(localFolder, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.99", e); } IFile child = link.getFile(childName); assertTrue("2.0", child.exists()); assertTrue("2.1", link.isLinked()); assertTrue("2.2", link.isLinked(IResource.NONE)); assertTrue("2.3", link.isLinked(IResource.CHECK_ANCESTORS)); assertTrue("2.1", !child.isLinked()); assertTrue("2.2", !child.isLinked(IResource.NONE)); assertTrue("2.3", child.isLinked(IResource.CHECK_ANCESTORS)); } /** * Tests the * {@link org.eclipse.core.resources.IResource#setLinkLocation(URI , int , IProgressMonitor )} * method. */ public void testsetLinkLocation() { // initially nothing is linked IResource[] toTest = new IResource[] {closedProject, existingFileInExistingProject, existingFolderInExistingFolder, existingFolderInExistingProject, existingProject, nonExistingFileInExistingFolder, nonExistingFileInExistingProject, nonExistingFileInOtherExistingProject, nonExistingFolderInExistingFolder, nonExistingFolderInExistingProject, nonExistingFolderInNonExistingFolder, nonExistingFolderInNonExistingProject, nonExistingFolderInOtherExistingProject, nonExistingProject, otherExistingProject}; for (int i = 0; i < toTest.length; i++) { assertTrue("1.0 " + toTest[i], !toTest[i].isLinked()); assertTrue("1.1 " + toTest[i], !toTest[i].isLinked(IResource.NONE)); assertTrue("1.2 " + toTest[i], !toTest[i].isLinked(IResource.CHECK_ANCESTORS)); } // create a link IFolder link = nonExistingFolderInExistingProject; try { link.createLink(localFolder, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.99", e); } IFile child = link.getFile(childName); assertTrue("2.0", child.exists()); assertTrue("2.1", link.isLinked()); assertTrue("2.2", link.isLinked(IResource.NONE)); assertTrue("2.3", link.isLinked(IResource.CHECK_ANCESTORS)); assertTrue("2.1", !child.isLinked()); assertTrue("2.2", !child.isLinked(IResource.NONE)); assertTrue("2.3", child.isLinked(IResource.CHECK_ANCESTORS)); try { link.createLink(existingFileInExistingProject.getLocationURI(), IResource.REPLACE, getMonitor()); } catch (CoreException e) { fail("2.99", e); } assertTrue("3.1", link.isLinked()); assertTrue("3.2", link.isLinked(IResource.NONE)); assertTrue("3.3", link.isLinked(IResource.CHECK_ANCESTORS)); assertTrue("3.4", link.getLocation().equals(existingFileInExistingProject.getLocation())); } /** * Tests swapping the link location. * This is a regression test for bug 268507 */ public void testSetLinkLocationSwapLinkedResource() { final IPath parentLoc = existingFolderInExistingProject.getLocation(); final IPath childLoc = existingFolderInExistingFolder.getLocation(); try { nonExistingFolderInExistingProject.createLink(parentLoc, IResource.NONE, getMonitor()); nonExistingFolderInOtherExistingProject.createLink(childLoc, IResource.NONE, getMonitor()); create(nonExistingFolderInOtherExistingProject.getFile("foo"), true); assertTrue("2.0", existingFolderInExistingFolder.members().length == 1); assertTrue("3.0", existingFolderInExistingFolder.members()[0].getName().equals("foo")); assertTrue("2.0", nonExistingFolderInOtherExistingProject.members().length == 1); assertTrue("3.0", nonExistingFolderInOtherExistingProject.members()[0].getName().equals("foo")); assertTrue("4.0", nonExistingFolderInExistingProject.members().length == 1); assertTrue("5.0", nonExistingFolderInExistingProject.members()[0].getName().equals(existingFolderInExistingFolder.getName())); } catch (CoreException e) { fail("1.0", e); } // Swap links around try { nonExistingFolderInExistingProject.createLink(childLoc, IResource.REPLACE, getMonitor()); nonExistingFolderInOtherExistingProject.createLink(parentLoc, IResource.REPLACE, getMonitor()); assertTrue("2.0", existingFolderInExistingFolder.members().length == 1); assertTrue("3.0", existingFolderInExistingFolder.members()[0].getName().equals("foo")); assertTrue(nonExistingFolderInExistingProject.getLocation().equals(childLoc)); assertTrue("2.0", nonExistingFolderInExistingProject.members().length == 1); assertTrue("3.0", nonExistingFolderInExistingProject.members()[0].getName().equals("foo")); assertTrue("4.0", nonExistingFolderInOtherExistingProject.members().length == 1); assertTrue("5.0", nonExistingFolderInOtherExistingProject.members()[0].getName().equals(existingFolderInExistingFolder.getName())); } catch (CoreException e) { fail("1.0", e); } } /** * Tests the * {@link org.eclipse.core.resources.IResource#setLinkLocation(IPath, int , IProgressMonitor )} * method. */ public void testsetLinkLocationPath() { //initially nothing is linked IResource[] toTest = new IResource[] {closedProject, existingFileInExistingProject, existingFolderInExistingFolder, existingFolderInExistingProject, existingProject, nonExistingFileInExistingFolder, nonExistingFileInExistingProject, nonExistingFileInOtherExistingProject, nonExistingFolderInExistingFolder, nonExistingFolderInExistingProject, nonExistingFolderInNonExistingFolder, nonExistingFolderInNonExistingProject, nonExistingFolderInOtherExistingProject, nonExistingProject, otherExistingProject}; for (int i = 0; i < toTest.length; i++) { assertTrue("1.0 " + toTest[i], !toTest[i].isLinked()); assertTrue("1.1 " + toTest[i], !toTest[i].isLinked(IResource.NONE)); assertTrue("1.2 " + toTest[i], !toTest[i].isLinked(IResource.CHECK_ANCESTORS)); } //create a link IFolder link = nonExistingFolderInExistingProject; try { link.createLink(localFolder, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.99", e); } IFile child = link.getFile(childName); assertTrue("2.0", child.exists()); assertTrue("2.1", link.isLinked()); assertTrue("2.2", link.isLinked(IResource.NONE)); assertTrue("2.3", link.isLinked(IResource.CHECK_ANCESTORS)); assertTrue("2.1", !child.isLinked()); assertTrue("2.2", !child.isLinked(IResource.NONE)); assertTrue("2.3", child.isLinked(IResource.CHECK_ANCESTORS)); try { link.createLink(existingFileInExistingProject.getLocation(), IResource.REPLACE, getMonitor()); } catch (CoreException e) { fail("2.99", e); } assertTrue("3.1", link.isLinked()); assertTrue("3.2", link.isLinked(IResource.NONE)); assertTrue("3.3", link.isLinked(IResource.CHECK_ANCESTORS)); assertTrue("3.4", link.getLocation().equals(existingFileInExistingProject.getLocation())); } /** * Specific testing of links within links. */ public void testLinkedFileInLinkedFolder() { //setup handles IProject project = existingProject; IFolder top = project.getFolder("topFolder"); IFolder linkedFolder = top.getFolder("linkedFolder"); IFolder subFolder = linkedFolder.getFolder("subFolder"); IFile linkedFile = subFolder.getFile("Link.txt"); IFileStore folderStore = getTempStore(); IFileStore subFolderStore = folderStore.getChild(subFolder.getName()); IFileStore fileStore = getTempStore(); IPath folderLocation = URIUtil.toPath(folderStore.toURI()); IPath fileLocation = URIUtil.toPath(fileStore.toURI()); try { //create the structure on disk subFolderStore.mkdir(EFS.NONE, getMonitor()); fileStore.openOutputStream(EFS.NONE, getMonitor()).close(); //create the structure in the workspace ensureExistsInWorkspace(top, true); linkedFolder.createLink(folderStore.toURI(), IResource.NONE, getMonitor()); linkedFile.createLink(fileStore.toURI(), IResource.NONE, getMonitor()); } catch (CoreException e) { fail("4.99", e); } catch (IOException e) { fail("4.99", e); } //assert locations assertEquals("1.0", folderLocation, linkedFolder.getLocation()); assertEquals("1.1", folderLocation.append(subFolder.getName()), subFolder.getLocation()); assertEquals("1.2", fileLocation, linkedFile.getLocation()); //assert URIs assertEquals("1.0", folderStore.toURI(), linkedFolder.getLocationURI()); assertEquals("1.1", subFolderStore.toURI(), subFolder.getLocationURI()); assertEquals("1.2", fileStore.toURI(), linkedFile.getLocationURI()); } /** * Automated test of IFile#createLink */ public void testLinkFile() { IResource[] interestingResources = new IResource[] {existingFileInExistingProject, nonExistingFileInExistingProject, nonExistingFileInExistingFolder}; IPath[] interestingLocations = new IPath[] {localFile, localFolder, nonExistingLocation}; IProgressMonitor[] monitors = new IProgressMonitor[] {new FussyProgressMonitor(), new CancelingProgressMonitor(), null}; Object[][] inputs = new Object[][] {interestingResources, interestingLocations, monitors}; new TestPerformer("LinkedResourceTest.testLinkFile") { protected static final String CANCELED = "canceled"; @Override public void cleanUp(Object[] args, int count) { super.cleanUp(args, count); try { doCleanup(); } catch (Exception e) { fail("invocation " + count + " failed to cleanup", e); } } @Override public Object invokeMethod(Object[] args, int count) throws Exception { IFile file = (IFile) args[0]; IPath location = (IPath) args[1]; IProgressMonitor monitor = (IProgressMonitor) args[2]; if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).prepare(); } try { file.createLink(location, IResource.NONE, monitor); } catch (OperationCanceledException e) { return CANCELED; } if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).sanityCheck(); } return null; } @Override public boolean shouldFail(Object[] args, int count) { IResource resource = (IResource) args[0]; IPath location = (IPath) args[1]; IProgressMonitor monitor = (IProgressMonitor) args[2]; if (monitor instanceof CancelingProgressMonitor) { return false; } //This resource already exists in the workspace if (resource.exists()) { return true; } IPath resolvedLocation = resolve(location); //The corresponding location in the local file system does not exist. if (!resolvedLocation.toFile().exists()) { return true; } //The workspace contains a resource of a different type at the same path as this resource if (getWorkspace().getRoot().findMember(resource.getFullPath()) != null) { return true; } //The parent of this resource does not exist. if (!resource.getParent().isAccessible()) { return true; } //The name of this resource is not valid (according to IWorkspace.validateName) if (!getWorkspace().validateName(resource.getName(), IResource.FOLDER).isOK()) { return true; } //The corresponding location in the local file system is occupied by a directory (as opposed to a file) if (resolvedLocation.toFile().isDirectory()) { return true; } //passed all failure case so it should succeed return false; } @Override public boolean wasSuccess(Object[] args, Object result, Object[] oldState) throws Exception { IFile resource = (IFile) args[0]; IPath location = (IPath) args[1]; IProgressMonitor monitor = (IProgressMonitor) args[2]; if (result == CANCELED) { return monitor instanceof CancelingProgressMonitor; } IPath resolvedLocation = resolve(location); if (!resource.exists() || !resolvedLocation.toFile().exists()) { return false; } if (!resource.getLocation().equals(resolvedLocation)) { return false; } if (!resource.isSynchronized(IResource.DEPTH_INFINITE)) { return false; } return true; } }.performTest(inputs); } /** * Automated test of IFolder#createLink */ public void testLinkFolder() { IResource[] interestingResources = new IResource[] {existingFolderInExistingProject, existingFolderInExistingFolder, nonExistingFolderInExistingProject, nonExistingFolderInNonExistingProject, nonExistingFolderInNonExistingFolder, nonExistingFolderInExistingFolder}; IPath[] interestingLocations = new IPath[] {localFile, localFolder, nonExistingLocation}; IProgressMonitor[] monitors = new IProgressMonitor[] {new FussyProgressMonitor(), new CancelingProgressMonitor(), null}; Object[][] inputs = new Object[][] {interestingResources, interestingLocations, monitors}; new TestPerformer("LinkedResourceTest.testLinkFolder") { protected static final String CANCELED = "canceled"; @Override public void cleanUp(Object[] args, int count) { super.cleanUp(args, count); try { doCleanup(); } catch (Exception e) { fail("invocation " + count + " failed to cleanup", e); } } @Override public Object invokeMethod(Object[] args, int count) throws Exception { IFolder folder = (IFolder) args[0]; IPath location = (IPath) args[1]; IProgressMonitor monitor = (IProgressMonitor) args[2]; if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).prepare(); } try { folder.createLink(location, IResource.NONE, monitor); } catch (OperationCanceledException e) { return CANCELED; } if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).sanityCheck(); } return null; } @Override public boolean shouldFail(Object[] args, int count) { IResource resource = (IResource) args[0]; IPath location = (IPath) args[1]; IProgressMonitor monitor = (IProgressMonitor) args[2]; if (monitor instanceof CancelingProgressMonitor) { return false; } //This resource already exists in the workspace if (resource.exists()) { return true; } //The corresponding location in the local file system does not exist. if (!resolve(location).toFile().exists()) { return true; } //The workspace contains a resource of a different type at the same path as this resource if (getWorkspace().getRoot().findMember(resource.getFullPath()) != null) { return true; } //The parent of this resource does not exist. if (!resource.getParent().isAccessible()) { return true; } //The name of this resource is not valid (according to IWorkspace.validateName) if (!getWorkspace().validateName(resource.getName(), IResource.FOLDER).isOK()) { return true; } //The corresponding location in the local file system is occupied by a file (as opposed to a directory) if (resolve(location).toFile().isFile()) { return true; } //passed all failure case so it should succeed return false; } @Override public boolean wasSuccess(Object[] args, Object result, Object[] oldState) throws Exception { IFolder resource = (IFolder) args[0]; IPath location = (IPath) args[1]; IProgressMonitor monitor = (IProgressMonitor) args[2]; if (result == CANCELED) { return monitor instanceof CancelingProgressMonitor; } IPath resolvedLocation = resolve(location); if (!resource.exists() || !resolvedLocation.toFile().exists()) { return false; } if (!resource.getLocation().equals(resolvedLocation)) { return false; } //ensure child exists if (!resource.getFile(childName).exists()) { return false; } return true; } }.performTest(inputs); } /** * Automated test of IWorkspace#validateLinkLocation and IWorkspace#validateLinkLocationURI with empty location * This is a regression test for bug 266662 */ public void testValidateEmptyLinkLocation() { IFolder folder = nonExistingFolderInExistingProject; IPath newLocation = new Path(""); URI newLocationURI = URIUtil.toURI(newLocation); try { IStatus linkedResourceStatus = getWorkspace().validateLinkLocation(folder, newLocation); assertEquals("1.0", IStatus.ERROR, linkedResourceStatus.getSeverity()); linkedResourceStatus = getWorkspace().validateLinkLocationURI(folder, newLocationURI); assertEquals("1.1", IStatus.ERROR, linkedResourceStatus.getSeverity()); } catch (Exception e) { fail("1.99", e); } } /** * Tests creating a linked resource whose location contains a colon character. */ public void testLocationWithColon() { //windows does not allow a location with colon in the name if (isWindows()) { return; } IFolder folder = nonExistingFolderInExistingProject; try { //Note that on *nix, "c:/temp" is a relative path with two segments //so this is treated as relative to an undefined path variable called "c:". IPath location = new Path("c:/temp"); folder.createLink(location, IResource.ALLOW_MISSING_LOCAL, getMonitor()); assertEquals("1.0", location, folder.getRawLocation()); } catch (CoreException e) { fail("1.99", e); } } /** * Tests the timestamp of a linked file when the local file is created or * deleted. See bug 34150 for more details. */ public void testModificationStamp() { IPath location = getRandomLocation(); IFile linkedFile = nonExistingFileInExistingProject; try { try { linkedFile.createLink(location, IResource.ALLOW_MISSING_LOCAL, getMonitor()); } catch (CoreException e) { fail("1.99", e); } assertEquals("1.0", IResource.NULL_STAMP, linkedFile.getModificationStamp()); //create local file try { resolve(location).toFile().createNewFile(); linkedFile.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); } catch (CoreException e) { fail("2.91", e); } catch (IOException e) { fail("2.92", e); } assertTrue("2.0", linkedFile.getModificationStamp() >= 0); //delete local file ensureDoesNotExistInFileSystem(resolve(location).toFile()); try { linkedFile.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); } catch (CoreException e) { fail("3.99", e); } assertEquals("4.0", IResource.NULL_STAMP, linkedFile.getModificationStamp()); } finally { Workspace.clear(resolve(location).toFile()); } } public void testMoveFile() { IResource[] sources = new IResource[] {nonExistingFileInExistingProject, nonExistingFileInExistingFolder}; IResource[] destinations = new IResource[] {existingProject, closedProject, nonExistingFileInOtherExistingProject, nonExistingFileInExistingFolder}; Boolean[] deepCopy = new Boolean[] {Boolean.TRUE, Boolean.FALSE}; IProgressMonitor[] monitors = new IProgressMonitor[] {new FussyProgressMonitor(), new CancelingProgressMonitor(), null}; Object[][] inputs = new Object[][] {sources, destinations, deepCopy, monitors}; new TestPerformer("LinkedResourceTest.testMoveFile") { protected static final String CANCELED = "canceled"; @Override public void cleanUp(Object[] args, int count) { super.cleanUp(args, count); try { doCleanup(); } catch (Exception e) { fail("invocation " + count + " failed to cleanup", e); } } @Override public Object invokeMethod(Object[] args, int count) throws Exception { IFile source = (IFile) args[0]; IResource destination = (IResource) args[1]; boolean isDeep = ((Boolean) args[2]).booleanValue(); IProgressMonitor monitor = (IProgressMonitor) args[3]; if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).prepare(); } try { source.createLink(localFile, IResource.NONE, null); source.move(destination.getFullPath(), isDeep ? IResource.NONE : IResource.SHALLOW, monitor); } catch (OperationCanceledException e) { return CANCELED; } if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).sanityCheck(); } return null; } @Override public boolean shouldFail(Object[] args, int count) { IFile source = (IFile) args[0]; IResource destination = (IResource) args[1]; boolean isDeep = ((Boolean) args[2]).booleanValue(); IProgressMonitor monitor = (IProgressMonitor) args[3]; if (monitor instanceof CancelingProgressMonitor) { return false; } IResource parent = destination.getParent(); if (!isDeep && parent == null) { return true; } if (!parent.isAccessible()) { return true; } if (source.equals(destination)) { return true; } if (source.getType() != destination.getType()) { return true; } if (destination.exists()) { return true; } //passed all failure case so it should succeed return false; } @Override public boolean wasSuccess(Object[] args, Object result, Object[] oldState) throws Exception { IResource destination = (IResource) args[1]; boolean isDeep = ((Boolean) args[2]).booleanValue(); IProgressMonitor monitor = (IProgressMonitor) args[3]; IPath sourceLocation = resolve(localFile); URI sourceLocationURI = URIUtil.toURI(sourceLocation); if (result == CANCELED) { return monitor instanceof CancelingProgressMonitor; } if (!destination.exists()) { return false; } //destination should only be linked for a shallow move if (isDeep) { if (destination.isLinked()) { return false; } if (resolve(localFile).equals(destination.getLocation())) { return false; } if (!destination.getProject().getLocation().isPrefixOf(destination.getLocation())) { return false; } } else { if (!destination.isLinked()) { return false; } if (!sourceLocation.equals(destination.getLocation())) { return false; } if (!sourceLocationURI.equals(destination.getLocationURI())) { return false; } } return true; } }.performTest(inputs); } public void testMoveFolder() { IResource[] sourceResources = new IResource[] {nonExistingFolderInExistingProject, nonExistingFolderInExistingFolder}; IResource[] destinationResources = new IResource[] {existingProject, closedProject, nonExistingProject, existingFolderInExistingProject, nonExistingFolderInOtherExistingProject, nonExistingFolderInExistingFolder}; IProgressMonitor[] monitors = new IProgressMonitor[] {new FussyProgressMonitor(), new CancelingProgressMonitor(), null}; Object[][] inputs = new Object[][] {sourceResources, destinationResources, monitors}; new TestPerformer("LinkedResourceTest.testMoveFolder") { protected static final String CANCELED = "canceled"; @Override public void cleanUp(Object[] args, int count) { super.cleanUp(args, count); try { doCleanup(); } catch (Exception e) { fail("invocation " + count + " failed to cleanup", e); } } @Override public Object invokeMethod(Object[] args, int count) throws Exception { IFolder source = (IFolder) args[0]; IResource destination = (IResource) args[1]; IProgressMonitor monitor = (IProgressMonitor) args[2]; if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).prepare(); } try { source.createLink(localFolder, IResource.NONE, null); source.move(destination.getFullPath(), IResource.SHALLOW, monitor); } catch (OperationCanceledException e) { return CANCELED; } if (monitor instanceof FussyProgressMonitor) { ((FussyProgressMonitor) monitor).sanityCheck(); } return null; } @Override public boolean shouldFail(Object[] args, int count) { IFolder source = (IFolder) args[0]; IResource destination = (IResource) args[1]; IProgressMonitor monitor = (IProgressMonitor) args[2]; if (monitor instanceof CancelingProgressMonitor) { return false; } IResource parent = destination.getParent(); if (parent == null) { return true; } if (source.equals(destination)) { return true; } if (source.getType() != destination.getType()) { return true; } if (!parent.isAccessible()) { return true; } if (destination.exists()) { return true; } //passed all failure case so it should succeed return false; } @Override public boolean wasSuccess(Object[] args, Object result, Object[] oldState) throws Exception { IResource destination = (IResource) args[1]; IProgressMonitor monitor = (IProgressMonitor) args[2]; if (result == CANCELED) { return monitor instanceof CancelingProgressMonitor; } if (!destination.exists()) { return false; } if (!destination.isLinked()) { return false; } if (!resolve(localFolder).equals(destination.getLocation())) { return false; } return true; } }.performTest(inputs); } /** * Tests moving a linked file resource that doesn't exist in the file system */ public void testMoveMissingFile() { IPath location = getRandomLocation(); IFile linkedFile = nonExistingFileInExistingProject; try { linkedFile.createLink(location, IResource.ALLOW_MISSING_LOCAL, getMonitor()); } catch (CoreException e) { fail("1.99", e); } IFile dest = existingProject.getFile("FailedMoveDest"); try { linkedFile.move(dest.getFullPath(), IResource.NONE, getMonitor()); fail("2.0"); } catch (CoreException e1) { //should fail } assertTrue("2.1", !dest.exists()); try { linkedFile.move(dest.getFullPath(), IResource.FORCE, getMonitor()); fail("2.2"); } catch (CoreException e1) { //should fail } assertTrue("2.3", !dest.exists()); } /** * Tests moving a linked folder that doesn't exist in the file system */ public void testMoveMissingFolder() { IPath location = getRandomLocation(); IFolder linkedFolder = nonExistingFolderInExistingProject; try { linkedFolder.createLink(location, IResource.ALLOW_MISSING_LOCAL, getMonitor()); } catch (CoreException e) { fail("1.99", e); } IFolder dest = existingProject.getFolder("FailedMoveDest"); try { linkedFolder.move(dest.getFullPath(), IResource.NONE, getMonitor()); fail("2.0"); } catch (CoreException e1) { //should fail } assertTrue("2.1", !dest.exists()); try { linkedFolder.move(dest.getFullPath(), IResource.FORCE, getMonitor()); fail("2.2"); } catch (CoreException e1) { //should fail } assertTrue("2.3", !dest.exists()); } public void testMoveProjectWithLinks() { IPath fileLocation = getRandomLocation(); IFile file = nonExistingFileInExistingProject; IFolder folder = nonExistingFolderInExistingProject; IFile childFile = folder.getFile(childName); IResource[] oldResources = new IResource[] {file, folder, existingProject, childFile}; try { try { createFileInFileSystem(resolve(fileLocation)); folder.createLink(localFolder, IResource.NONE, getMonitor()); file.createLink(fileLocation, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.0", e); } //move the project IProject destination = getWorkspace().getRoot().getProject("MoveTargetProject"); IFile newFile = destination.getFile(file.getProjectRelativePath()); IFolder newFolder = destination.getFolder(folder.getProjectRelativePath()); IFile newChildFile = newFolder.getFile(childName); IResource[] newResources = new IResource[] {destination, newFile, newFolder, newChildFile}; assertDoesNotExistInWorkspace("2.0", destination); try { existingProject.move(destination.getFullPath(), IResource.SHALLOW, getMonitor()); } catch (CoreException e) { fail("2.1", e); } assertExistsInWorkspace("3.0", newResources); assertDoesNotExistInWorkspace("3.1", oldResources); assertTrue("3.2", newFile.isLinked()); assertEquals("3.3", resolve(fileLocation), newFile.getLocation()); assertTrue("3.4", newFolder.isLinked()); assertEquals("3.5", resolve(localFolder), newFolder.getLocation()); assertTrue("3.6", destination.isSynchronized(IResource.DEPTH_INFINITE)); //now do a deep move back to the original project try { destination.move(existingProject.getFullPath(), IResource.NONE, getMonitor()); } catch (CoreException e) { fail("5.0", e); } assertExistsInWorkspace("5.1", oldResources); assertDoesNotExistInWorkspace("5.2", newResources); assertTrue("5.3", !file.isLinked()); assertTrue("5.4", !folder.isLinked()); assertEquals("5.5", existingProject.getLocation().append(file.getProjectRelativePath()), file.getLocation()); assertEquals("5.6", existingProject.getLocation().append(folder.getProjectRelativePath()), folder.getLocation()); assertTrue("5.7", existingProject.isSynchronized(IResource.DEPTH_INFINITE)); assertTrue("5.8", destination.isSynchronized(IResource.DEPTH_INFINITE)); } finally { Workspace.clear(resolve(fileLocation).toFile()); } } /** * Tests bug 117402. */ public void testMoveProjectWithLinks2() { IPath fileLocation = getRandomLocation(); IFile linkedFile = existingProject.getFile("(test)"); try { try { createFileInFileSystem(resolve(fileLocation), getRandomContents()); linkedFile.createLink(fileLocation, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.0", e); } //move the project IProject destination = getWorkspace().getRoot().getProject("CopyTargetProject"); try { existingProject.move(destination.getFullPath(), IResource.SHALLOW, getMonitor()); } catch (CoreException e) { fail("2.0", e); } IFile newFile = destination.getFile(linkedFile.getProjectRelativePath()); assertTrue("3.0", newFile.isLinked()); assertEquals("3.1", resolve(fileLocation), newFile.getLocation()); } finally { Workspace.clear(resolve(fileLocation).toFile()); } } /** * Tests bug 298849. */ public void testMoveFolderWithLinks() { // create a folder IFolder folderWithLinks = existingProject.getFolder(getUniqueString()); try { folderWithLinks.create(true, true, getMonitor()); } catch (CoreException e) { fail("1.0", e); } IPath fileLocation = getRandomLocation(); try { createFileInFileSystem(resolve(fileLocation), getRandomContents()); // create a linked file in the folder IFile linkedFile = folderWithLinks.getFile(getUniqueString()); try { linkedFile.createLink(fileLocation, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("2.0", e); } // there should be an entry in .project for the linked file String string = readStringInFileSystem(existingProject.getFile(".project")); assertTrue("3.0", string.indexOf(linkedFile.getProjectRelativePath().toString()) != -1); // move the folder try { folderWithLinks.move(otherExistingProject.getFolder(getUniqueString()).getFullPath(), IResource.SHALLOW | IResource.ALLOW_MISSING_LOCAL, getMonitor()); } catch (CoreException e) { fail("4.0", e); } // both the folder and link in the source project should not exist assertFalse("5.0", folderWithLinks.exists()); assertFalse("6.0", linkedFile.exists()); // the project description should not contain links HashMap<IPath, LinkDescription> links = null; try { links = ((ProjectDescription) existingProject.getDescription()).getLinks(); } catch (CoreException e) { fail("7.0", e); } assertNull("8.0", links); // and the entry from .project should be removed string = readStringInFileSystem(existingProject.getFile(".project")); assertEquals("9.0", -1, string.indexOf(linkedFile.getProjectRelativePath().toString())); } finally { Workspace.clear(resolve(fileLocation).toFile()); } } public void testNatureVeto() { //note: simpleNature has the link veto turned on. //test create link on project with nature veto try { IProjectDescription description = existingProject.getDescription(); description.setNatureIds(new String[] {NATURE_SIMPLE}); existingProject.setDescription(description, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.0", e); } try { nonExistingFolderInExistingProject.createLink(localFolder, IResource.NONE, getMonitor()); fail("1.1"); } catch (CoreException e) { //should fail } try { nonExistingFileInExistingProject.createLink(localFile, IResource.NONE, getMonitor()); fail("1.2"); } catch (CoreException e) { //should fail } //test add nature with veto to project that already has link try { existingProject.delete(IResource.FORCE, getMonitor()); existingProject.create(getMonitor()); existingProject.open(getMonitor()); nonExistingFolderInExistingProject.createLink(localFolder, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("2.0", e); } try { IProjectDescription description = existingProject.getDescription(); description.setNatureIds(new String[] {NATURE_SIMPLE}); existingProject.setDescription(description, IResource.NONE, getMonitor()); fail("3.0"); } catch (CoreException e) { //should fail } } /** * Tests creating a link within a link, and ensuring that both links still * exist when the project is closed/opened (bug 177367). */ public void testNestedLink() { final IFileStore store1 = getTempStore(); final IFileStore store2 = getTempStore(); URI location1 = store1.toURI(); URI location2 = store2.toURI(); //folder names are important here, because we want a certain order in the link hash map IFolder link = existingProject.getFolder("aA"); IFolder linkChild = link.getFolder("b"); try { store1.mkdir(EFS.NONE, getMonitor()); store2.mkdir(EFS.NONE, getMonitor()); link.createLink(location1, IResource.NONE, getMonitor()); linkChild.createLink(location2, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("0.99", e); } assertTrue("1.0", link.exists()); assertTrue("1.1", link.isLinked()); assertTrue("1.2", linkChild.exists()); assertTrue("1.3", linkChild.isLinked()); assertEquals("1.4", location1, link.getLocationURI()); assertEquals("1.5", location2, linkChild.getLocationURI()); //now delete and recreate the project try { existingProject.delete(IResource.NEVER_DELETE_PROJECT_CONTENT, getMonitor()); existingProject.create(getMonitor()); existingProject.open(IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.99", e); } assertTrue("2.0", link.exists()); assertTrue("2.1", link.isLinked()); assertTrue("2.2", linkChild.exists()); assertTrue("2.3", linkChild.isLinked()); assertEquals("2.4", location1, link.getLocationURI()); assertEquals("2.5", location2, linkChild.getLocationURI()); } /** * Create a project with a linked resource at depth > 2, and refresh it. */ public void testRefreshDeepLink() { IFolder link = nonExistingFolderInExistingFolder; IPath linkLocation = localFolder; IPath localChild = linkLocation.append("Child"); IFile linkChild = link.getFile(localChild.lastSegment()); createFileInFileSystem(resolve(localChild)); try { link.createLink(linkLocation, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("0.99", e); } assertTrue("1.0", link.exists()); assertTrue("1.1", linkChild.exists()); try { IProject project = link.getProject(); project.refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); } catch (CoreException e) { fail("1.99", e); } assertTrue("2.0", link.exists()); assertTrue("2.1", linkChild.exists()); } public void testLinkedFolderWithOverlappingLocation_Bug293935_() { IWorkspace workspace = getWorkspace(); IPath projectLocation = existingProject.getLocation(); IFolder folderByIPath = existingProject.getFolder("overlappingLinkedFolderByIPath"); assertTrue("1.1", !workspace.validateLinkLocation(folderByIPath, projectLocation).isOK()); try { folderByIPath.createLink(projectLocation, IResource.NONE, getMonitor()); fail("1.2"); } catch (CoreException e) { // expected to fail } URI projectLocationURI = existingProject.getLocationURI(); IFolder folderByURI = existingProject.getFolder("overlappingLinkedFolderByURI"); assertTrue("2.1", !workspace.validateLinkLocationURI(folderByURI, projectLocationURI).isOK()); try { folderByURI.createLink(projectLocationURI, IResource.NONE, getMonitor()); fail("2.2"); } catch (CoreException e) { // expected to fail just like when creating link by IPath } // device is missing IPath projectLocationWithoutDevice = projectLocation.setDevice(null); IFolder folderByUnixLikeIPath = existingProject.getFolder("overlappingLinkedFolderByUnixLikeIPath"); assertTrue("3.1", !workspace.validateLinkLocation(folderByUnixLikeIPath, projectLocationWithoutDevice).isOK()); try { folderByUnixLikeIPath.createLink(projectLocationWithoutDevice, IResource.NONE, getMonitor()); fail("3.2"); } catch (CoreException e) { // expected to fail } URI projectLocationURIWithoutDevice = URIUtil.toURI(projectLocationWithoutDevice.toString()); IFolder folderByUnixLikeURI = existingProject.getFolder("overlappingLinkedFolderByUnixLikeURI"); assertTrue("4.1", !workspace.validateLinkLocationURI(folderByUnixLikeURI, projectLocationURIWithoutDevice).isOK()); try { folderByUnixLikeURI.createLink(projectLocationURIWithoutDevice, IResource.NONE, getMonitor()); fail("4.2"); } catch (CoreException e) { // expected to fail } } public void testLinkedFolderWithSymlink_Bug338010() { // Only activate this test if testing of symbolic links is possible. if (!canCreateSymLinks()) { return; } IPath baseLocation = getRandomLocation(); IPath resolvedBaseLocation = resolve(baseLocation); deleteOnTearDown(resolvedBaseLocation); IPath symlinkTarget = resolvedBaseLocation.append("dir1/target"); symlinkTarget.toFile().mkdirs(); createSymLink(resolvedBaseLocation.toFile(), "symlink", symlinkTarget.toOSString(), true); IPath linkChildLocation = baseLocation.append("symlink/dir2"); IPath resolvedLinkChildLocation = resolve(linkChildLocation); File linkChild = resolvedLinkChildLocation.toFile(); linkChild.mkdir(); assertTrue("Could not create link at location: " + linkChild, linkChild.exists()); IFolder folder = nonExistingFolderInExistingProject; try { folder.createLink(linkChildLocation, IResource.NONE, getMonitor()); } catch (CoreException e) { fail("1.1", e); } // Check that the symlink is preserved. assertEquals("1.2", resolvedLinkChildLocation, folder.getLocation()); } /** * Tests deleting of the target of a linked folder that itself is a symbolic link. */ public void testDeleteLinkTarget_Bug507084() throws Exception { // Only activate this test if testing of symbolic links is possible. if (!canCreateSymLinks()) { return; } IPath baseLocation = getRandomLocation(); IPath resolvedBaseLocation = resolve(baseLocation); deleteOnTearDown(resolvedBaseLocation); IPath symlinkTarget = resolvedBaseLocation.append("dir1/A"); symlinkTarget.append("B/C").toFile().mkdirs(); IPath linkParentDir = resolvedBaseLocation.append("dir2"); linkParentDir.toFile().mkdirs(); createSymLink(linkParentDir.toFile(), "symlink", symlinkTarget.toOSString(), true); IFolder folder = nonExistingFolderInExistingProject; IPath symLink = linkParentDir.append("symlink"); folder.createLink(symLink, IResource.NONE, getMonitor()); assertTrue("1.1", folder.exists()); assertTrue("1.2", folder.getFolder("B/C").exists()); assertEquals("1.3", symLink, folder.getLocation()); // Delete the symlink and the directory that contains it. symLink.toFile().delete(); linkParentDir.toFile().delete(); // Check that the directory that contained the symlink has been deleted. assertFalse("2.1", linkParentDir.toFile().exists()); // Refresh the project. folder.getParent().refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); // Check that the linked folder still exists. assertTrue("3.1", folder.exists()); // Check that the contents of the linked folder no longer exist. assertFalse("3.2", folder.getFolder("B").exists()); assertFalse("3.3", folder.getFolder("B/C").exists()); } }