blob: b45c7aa2ad046f92c8d37734b27def224141e811 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2013 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.tests.ccvs.core.subscriber;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.util.Util;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.subscribers.ISubscriberChangeEvent;
import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.CVSSyncTreeSubscriber;
import org.eclipse.team.internal.ccvs.core.CVSTag;
import org.eclipse.team.internal.ccvs.core.CVSTeamProvider;
import org.eclipse.team.internal.ccvs.core.ICVSFile;
import org.eclipse.team.internal.ccvs.core.ICVSFolder;
import org.eclipse.team.internal.ccvs.core.ICVSResource;
import org.eclipse.team.internal.ccvs.core.client.Command;
import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.ui.operations.RepositoryProviderOperation;
import org.eclipse.team.tests.ccvs.core.CVSTestSetup;
import org.eclipse.team.tests.ccvs.core.TeamCVSTestPlugin;
import org.eclipse.team.tests.ccvs.core.mappings.model.ModelProject;
import org.eclipse.team.tests.ccvs.core.mappings.model.mapping.ModelResourceMapping;
import org.eclipse.team.tests.ccvs.ui.ModelParticipantSyncInfoSource;
import junit.framework.Test;
import junit.framework.TestSuite;
/**
* This class tests the CVSWorkspaceSubscriber
*/
public class CVSWorkspaceSubscriberTest extends CVSSyncSubscriberTest {
/**
* Constructor for CVSProviderTest
*/
public CVSWorkspaceSubscriberTest() {
super();
}
/**
* Constructor for CVSProviderTest
*/
public CVSWorkspaceSubscriberTest(String name) {
super(name);
}
public static Test suite() {
String testName = System.getProperty("eclipse.cvs.testName");
if (testName == null) {
TestSuite suite = new TestSuite(CVSWorkspaceSubscriberTest.class);
return new CVSTestSetup(suite);
} else {
return new CVSTestSetup(new CVSWorkspaceSubscriberTest(testName));
}
}
@Override
protected boolean isFailOnSyncInfoMismatch() {
return CVSTestSetup.FAIL_ON_BAD_DIFF ;
}
protected CVSSyncTreeSubscriber getSubscriber() throws TeamException {
return (CVSSyncTreeSubscriber)getWorkspaceSubscriber();
}
/*
* The shareProject method is invoked when creating new projects.
*
* @see
* org.eclipse.team.tests.ccvs.core.EclipseTest#shareProject(org.eclipse.core.
* resources.IProject)
*/
@Override
protected void shareProject(final IProject project) throws TeamException, CoreException {
mapNewProject(project);
// Everything should be outgoing addition except he project
assertSyncEquals(project.getName(), getSubscriber(), project, SyncInfo.IN_SYNC);
assertAllSyncEquals(project.members(true), SyncInfo.OUTGOING | SyncInfo.ADDITION, IResource.DEPTH_INFINITE);
commitNewProject(project);
// Everything should be in-sync
assertAllSyncEquals(project, SyncInfo.IN_SYNC, IResource.DEPTH_INFINITE);
}
protected void assertAllSyncEquals(final IResource rootResource, final int kind, int depth) throws CoreException {
if (!rootResource.exists() && !rootResource.isPhantom()) {
assertTrue(kind == SyncInfo.IN_SYNC);
return;
}
rootResource.accept((IResourceVisitor) resource -> {
assertSyncEquals(rootResource.getName(), getSubscriber(), resource, kind);
return true;
}, depth, true);
}
private void assertAllSyncEquals(IResource[] resources, int kind, int depth) throws CoreException {
for (IResource resource : resources) {
assertAllSyncEquals(resource, kind, depth);
}
}
@Override
protected void setContentsAndEnsureModified(IFile file) throws CoreException, TeamException {
// The delta will indicate to any interested parties that the sync state of the
// file has changed
super.setContentsAndEnsureModified(file);
SyncInfo info = getSyncInfoSource().getSyncInfo(getSubscriber(), file);
int kind = info.getKind();
assertTrue((kind & SyncInfo.CHANGE_MASK) == SyncInfo.CHANGE);
assertTrue((kind & SyncInfo.OUTGOING) > 0);
}
private void assertSyncEquals(String string, IProject project, String[] strings, boolean refresh, int[] kinds) throws CoreException, TeamException {
assertSyncEquals(string, getSubscriber(), project, strings, refresh, kinds);
}
private void assertSyncEquals(IProject project, String[] strings, boolean refresh, int[] kinds) throws CoreException, TeamException {
assertSyncEquals(getName(), getSubscriber(), project, strings, refresh, kinds);
}
private void assertSyncEquals(String message, IResource resource, int syncKind) throws CoreException {
assertSyncEquals(message, getSubscriber(), resource, syncKind);
}
@Override
protected void addResources(IResource[] resources) throws TeamException, CVSException, CoreException {
// first, get affected children
IResource[] affectedChildren = collect(resources, new ResourceCondition() {
@Override
public boolean matches(IResource resource) throws TeamException {
ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
return (!cvsResource.isManaged() && !cvsResource.isIgnored());
}
}, IResource.DEPTH_INFINITE);
// also get affected parents
IResource[] affectedParents = collectAncestors(resources, new ResourceCondition() {
@Override
public boolean matches(IResource resource) throws CoreException, TeamException {
if (resource.getType() == IResource.PROJECT) return false;
ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
return (!cvsResource.isManaged() && !cvsResource.isIgnored());
}
});
Set<IResource> affected = new HashSet<>();
affected.addAll(Arrays.asList(affectedChildren));
affected.addAll(Arrays.asList(affectedParents));
registerSubscriberListener();
super.addResources(resources);
ISubscriberChangeEvent[] changes = deregisterSubscriberListener();
assertSyncChangesMatch(changes, affected.toArray(new IResource[affected.size()]));
for (IResource resource : resources) {
if (resource.getType() == IResource.FILE) {
assertSyncEquals("Add", resource, SyncInfo.OUTGOING | SyncInfo.ADDITION);
} else {
// TODO: a folder should be in sync but isn't handled properly
assertSyncEquals("Add", resource, SyncInfo.IN_SYNC);
}
}
}
private void registerSubscriberListener() throws TeamException {
registerSubscriberListener(getSubscriber());
}
@Override
protected void deleteResources(IResource[] resources) throws TeamException, CoreException {
IResource[] affected = collect(resources, new ResourceCondition(), IResource.DEPTH_INFINITE);
registerSubscriberListener();
super.deleteResources(resources);
ISubscriberChangeEvent[] changes = deregisterSubscriberListener();
assertSyncChangesMatch(changes, affected);
for (IResource resource : resources) {
// After deletion, folders should be in-sync while files should be outgoing deletions
if (resource.getType() == IResource.FILE) {
assertSyncEquals("Delete", resource, SyncInfo.OUTGOING | SyncInfo.DELETION);
} else {
assertSyncEquals("Delete", resource, SyncInfo.IN_SYNC);
}
}
}
private ISubscriberChangeEvent[] deregisterSubscriberListener() throws TeamException {
return deregisterSubscriberListener(getSubscriber());
}
@Override
protected void commitResources(IResource[] resources, int depth) throws TeamException, CVSException, CoreException {
IResource[] affected = collect(resources, new ResourceCondition() {
@Override
public boolean matches(IResource resource) throws CoreException, TeamException {
ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
return (!cvsResource.isFolder() && cvsResource.isManaged() && cvsResource.isModified(DEFAULT_MONITOR));
}
}, IResource.DEPTH_INFINITE);
registerSubscriberListener();
super.commitResources(resources, depth);
ISubscriberChangeEvent[] changes = deregisterSubscriberListener();
assertSyncChangesMatch(changes, affected);
for (IResource resource : resources) {
if (resource.exists())
assertSyncEquals("Commit", resource, SyncInfo.IN_SYNC);
}
}
@Override
protected void unmanageResources(IResource[] resources) throws CoreException, TeamException {
IResource[] affected = collect(resources, new ResourceCondition() {
@Override
public boolean matches(IResource resource) throws CoreException, TeamException {
ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
return (cvsResource.isManaged());
}
}, IResource.DEPTH_INFINITE);
registerSubscriberListener();
super.unmanageResources(resources);
ISubscriberChangeEvent[] changes = deregisterSubscriberListener();
assertSyncChangesMatch(changes, affected);
for (IResource resource : resources) {
if (resource.exists())
assertSyncEquals("Unmanage", resource, SyncInfo.IN_SYNC);
}
}
/******************************************************************
* Subscriber Actions: commit/update and override and commit/update
* These actions are those contributed to the Synchronize View by
* the CVS plugin.
******************************************************************/
public IResource[] update(IContainer container, String[] hierarchy) throws CoreException {
IResource[] resources = getResources(container, hierarchy);
getSyncInfoSource().updateResources(getSubscriber(), resources);
return resources;
}
public IResource[] commit(IContainer container, String[] hierarchy) throws CoreException {
IResource[] resources = getResources(container, hierarchy);
getSyncInfoSource().commitResources(getSubscriber(), resources);
return resources;
}
public IResource[] overrideAndUpdate(IContainer container, String[] hierarchy, boolean shouldPrompt) throws CoreException, TeamException {
IResource[] resources = getResources(container, hierarchy);
getSyncInfoSource().overrideAndUpdateResources(getSubscriber(), shouldPrompt, resources);
return resources;
}
public IResource[] overrideAndCommit(IContainer container, String[] hierarchy, boolean shouldPrompt) throws CoreException, TeamException {
IResource[] resources = getResources(container, hierarchy);
getSyncInfoSource().overrideAndCommitResources(getSubscriber(), resources);
return resources;
}
/******************************************************************
* Tests
******************************************************************/
public void testBug302163WithoutModel() throws CoreException {
// Create a model project and share it
IProject modelProject = getUniqueTestProject("test1");
buildResources(modelProject, new String[] { "file.mod", "f1.moe" }, true);
modelProject.getFile("file.mod").setContents(new ByteArrayInputStream(("\nf1.moe").getBytes()), false, true, null);
shareProject(modelProject);
assertValidCheckout(modelProject);
// Checkout and modify a copy of the model project
IProject copyModelProject = checkoutCopy(modelProject, "-copy");
copyModelProject.getFile("file.mod").setContents(new ByteArrayInputStream(("\nf1.moe\nf2.moe").getBytes()), false, true, null);
commitProject(copyModelProject);
try {
RepositoryProviderOperation.consultModelsWhenBuildingScope = true;
setSyncSource(new SyncInfoSource());
refresh(getSubscriber(), modelProject);
// Update the "file.mod" file
try {
update(modelProject, new String[] { "file.mod" });
} catch (CVSException e) {
fail("Update without models failed", e);
}
} finally {
// Reset settings
RepositoryProviderOperation.consultModelsWhenBuildingScope = false;
setSyncSource(new ModelParticipantSyncInfoSource());
}
}
public void testBug302163WithModel() throws CoreException {
// Create a project being a part of the model, share it
IProject project = createProject("test", new String[] { "file1.txt" });
ModelResourceMapping.projectName = project.getName();
// Create a model project and share it
IProject modelProject = getUniqueTestProject("test1");
buildResources(modelProject, new String[] { "file.mod", "f1.moe" }, true);
modelProject.getFile("file.mod").setContents(new ByteArrayInputStream(("\nf1.moe").getBytes()), false, true, null);
ModelProject.makeModProject(modelProject, new NullProgressMonitor());
shareProject(modelProject);
assertValidCheckout(modelProject);
// Checkout and modify a copy of the model project
IProject copyModelProject = checkoutCopy(modelProject, "-copy");
copyModelProject.getFile("file.mod").setContents(new ByteArrayInputStream(("\nf1.moe\nf2.moe").getBytes()), false, true, null);
commitProject(copyModelProject);
try {
RepositoryProviderOperation.consultModelsWhenBuildingScope = true;
setSyncSource(new SyncInfoSource());
refresh(getSubscriber(), modelProject);
// Update the "file.mod" file
try {
update(modelProject, new String[] { "file.mod" });
} catch (CVSException e) {
fail("Update without models failed", e);
}
} finally {
// Reset settings
RepositoryProviderOperation.consultModelsWhenBuildingScope = false;
setSyncSource(new ModelParticipantSyncInfoSource());
}
}
/*
* Perform a simple test that checks for the different types of incoming changes
*/
public void testIncomingChanges() throws IOException, TeamException, CoreException {
// Create a test project
IProject project = createProject("testIncomingChanges", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Checkout and modify a copy
IProject copy = checkoutCopy(project, "-copy");
setContentsAndEnsureModified(copy.getFile("folder1/a.txt"));
addResources(copy, new String[] { "folder2/folder3/add.txt" }, false);
deleteResources(copy, new String[] {"folder1/b.txt"}, false);
commitProject(copy);
// Get the sync tree for the project
assertSyncEquals("testIncomingChanges", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.INCOMING | SyncInfo.CHANGE,
SyncInfo.INCOMING | SyncInfo.DELETION,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION});
// Catch up to the incoming changes
update(
project,
new String[] {
"folder1/a.txt",
"folder1/b.txt",
"folder2/",
"folder2/folder3/",
"folder2/folder3/add.txt"});
// Verify that we are in sync (except for "folder1/b.txt", which was deleted)
assertSyncEquals("testIncomingChanges", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC});
// Ensure "folder1/b.txt" was deleted
assertDeleted("testIncomingChanges", project, new String[] {"folder1/b.txt"});
// Verify that the copy equals the original
assertEquals(project, copy);
}
/*
* Perform a simple test that checks for the different types of outgoing changes
*/
public void testOutgoingChanges() throws TeamException, CoreException {
// Create a test project (which commits it as well)
IProject project = createProject("testOutgoingChanges", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Make some modifications
setContentsAndEnsureModified(project.getFile("folder1/a.txt"));
addResources(project, new String[] { "folder2/folder3/add.txt" }, false);
deleteResources(project, new String[] {"folder1/b.txt"}, false);
// Get the sync tree for the project
assertSyncEquals("testOutgoingChanges", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.CHANGE,
SyncInfo.OUTGOING | SyncInfo.DELETION,
SyncInfo.IN_SYNC, /* adding a folder creates it remotely */
SyncInfo.IN_SYNC, /* adding a folder creates it remotely */
SyncInfo.OUTGOING | SyncInfo.ADDITION});
// Commit the changes
commit(project, new String[] {"folder1/a.txt", "folder1/b.txt", "folder2/folder3/add.txt"});
// Ensure we're in sync
assertSyncEquals("testOutgoingChanges", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC});
// Ensure deleted resource "folder1/b.txt" no longer exists
assertDeleted("testOutgoingChanges", project, new String[] {"folder1/b.txt"});
}
public void testOverideAndUpdateSimple() throws CVSException, CoreException, IOException {
IProject project = createProject("testOutgoingChangesOverideAndUpdate", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Make some modifications
setContentsAndEnsureModified(project.getFile("folder1/a.txt"));
addResources(project, new String[] { "folder2/folder3/add.txt" }, false);
deleteResources(project, new String[] {"folder1/b.txt"}, false);
// Get the sync tree for the project
assertSyncEquals("testOutgoingChangesOverwrite", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.CHANGE,
SyncInfo.OUTGOING | SyncInfo.DELETION,
SyncInfo.IN_SYNC, /* adding a folder creates it remotely */
SyncInfo.IN_SYNC, /* adding a folder creates it remotely */
SyncInfo.OUTGOING | SyncInfo.ADDITION});
// Revert the changes
overrideAndUpdate(project, new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"}, true /* should prompt */);
// Ensure we're in sync
assertSyncEquals("testOutgoingChangesOverwrite", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC});
// Ensure deleted resource is re-created
assertExistsInWorkspace("testOutgoingChangesOverwrite", project.getFile(new Path("folder1/b.txt")));
// Test conflicting changes
IProject copy = checkoutCopy(project, "-copy");
appendText(copy.getFile("file1.txt"), "prefix" + eol, true);
setContentsAndEnsureModified(copy.getFile("folder1/a.txt"), "Use a custom string to avoid intermittent errors!");
commitProject(copy);
// Make the same modifications to the original (We need to test both M and C!!!)
appendText(project.getFile("file1.txt"), eol + "postfix", false); // This will test merges (M)
setContentsAndEnsureModified(project.getFile("folder1/a.txt"));
// Get the sync tree for the project
assertSyncEquals("testFileConflict", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt"},
true, new int[] {
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
SyncInfo.IN_SYNC,
SyncInfo.CONFLICTING | SyncInfo.CHANGE });
// Revert the changes
overrideAndUpdate(project, new String[] { "file1.txt", "folder1/", "folder1/a.txt"}, true /* should prompt */);
assertSyncEquals("testFileConflict", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC});
}
/*
* Perform a simple test that checks for the different types of outgoing changes
*/
public void testOverrideOutgoingChanges() throws IOException, TeamException, CoreException {
// Create a test project (which commits it as well)
IProject project = createProject("testOverrideOutgoingChanges", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Checkout a copy for later verification
IProject original = checkoutCopy(project, "-copy");
// Make some modifications
setContentsAndEnsureModified(project.getFile("folder1/a.txt"));
addResources(project, new String[] { "folder2/folder3/add.txt" }, false);
deleteResources(project, new String[] {"folder1/b.txt"}, false);
// Get the sync tree for the project
assertSyncEquals("testOverrideOutgoingChanges", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.CHANGE,
SyncInfo.OUTGOING | SyncInfo.DELETION,
SyncInfo.IN_SYNC, /* adding a folder creates it remotely */
SyncInfo.IN_SYNC, /* adding a folder creates it remotely */
SyncInfo.OUTGOING | SyncInfo.ADDITION});
// Override the changes
overrideAndUpdate(
project,
new String[] {
"folder1/a.txt",
"folder1/b.txt",
"folder2/folder3/add.txt"},
true /* should prompt */);
// Ensure added resources no longer exist
assertDeleted("testOverrideOutgoingChanges", project, new String[] {"folder2/", "folder2/folder3/","folder2/folder3/add.txt"});
// Ensure other resources are in sync
assertSyncEquals("testOverrideOutgoingChanges", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder2/"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC});
// Verify that the original has reverted to its original contents
assertEquals(project, original);
}
/*
* Perform a test that checks for outgoing changes that are CVS questionables (no add or remove)
*/
public void testOutgoingQuestionables() throws TeamException, CoreException {
// Create a test project (which commits it as well)
IProject project = createProject("testIncomingChanges", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Create a new file without adding it to version control
buildResources(project, new String[] {"folder2/folder3/add.txt"}, false);
// Delete a file without an explicit cvs remove
// NOTE: This will result in an implicit cvs remove
IFile file = project.getFile("folder1/b.txt");
file.delete(true, DEFAULT_MONITOR);
// Get the sync tree for the project
assertSyncEquals("testOutgoingQuestionables", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.DELETION,
SyncInfo.OUTGOING | SyncInfo.ADDITION,
SyncInfo.OUTGOING | SyncInfo.ADDITION,
SyncInfo.OUTGOING | SyncInfo.ADDITION});
commit(project, new String[] {"folder1/b.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"});
// Ensure we are in sync
assertSyncEquals("testOutgoingQuestionables", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC});
// Ensure "folder1/b.txt" was deleted
assertDeleted("testOutgoingQuestionables", project, new String[] {"folder1/b.txt"});
}
/*
* Test simple file conflicts
*/
public void testFileConflict() throws IOException, TeamException, CoreException {
// Create a test project (which commits it as well)
IProject project = createProject("testFileConflict", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Set the contents of file1.txt to ensure proper merging
setContentsAndEnsureModified(project.getFile("file1.txt"), "Use a custom string" + eol + " to ensure proper merging");
commitProject(project);
// Checkout a copy and make some modifications
IProject copy = checkoutCopy(project, "-copy");
appendText(copy.getFile("file1.txt"), "prefix" + eol, true);
setContentsAndEnsureModified(copy.getFile("folder1/a.txt"), "Use a custom string to avoid intermittent errors!");
commitProject(copy);
// Make the same modifications to the original (We need to test both M and C!!!)
appendText(project.getFile("file1.txt"), eol + "postfix", false); // This will test merges (M)
setContentsAndEnsureModified(project.getFile("folder1/a.txt"));
// Get the sync tree for the project
assertSyncEquals("testFileConflict", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt"},
true, new int[] {
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
SyncInfo.IN_SYNC,
SyncInfo.CONFLICTING | SyncInfo.CHANGE });
// Catch up to the file1.txt conflict using UPDATE
update(
project,
new String[] {"file1.txt"});
assertSyncEquals("testFileConflict", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt"},
true, new int[] {
SyncInfo.OUTGOING | SyncInfo.CHANGE,
SyncInfo.IN_SYNC,
SyncInfo.CONFLICTING | SyncInfo.CHANGE });
// Release the folder1/a.txt conflict by merging and then committing
overrideAndCommit(project, new String[] {"folder1/a.txt"}, true);
commit(project, new String[] {"file1.txt"});
assertSyncEquals("testFileConflict", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC });
}
/*
* Test conflicts involving additions
*/
public void testAdditionConflicts() throws CoreException {
// CASE 1: The user adds (using CVS add) a remotely added file
// (a) catch-up is simply get?
// (b) release must do a merge
// CASE 2: The user adds (but not using cvs add) a remotely added file
// (a) catch-up is simply get?
// (b) release must do a merge
// CASE 3: The user adds a remotely added then deleted file
// catch-up is not applicable
// release is normal
// Create a test project (which commits it as well) and add an uncommitted resource
IProject project = createProject("testAdditionConflicts", new String[] { "file.txt"});
addResources(project, new String[] { "add1a.txt", "add1b.txt" }, false);
addResources(project, new String[] { "add3.txt" }, false);
buildResources(project, new String[] {"add2a.txt", "add2b.txt"}, false);
// Checkout a copy, add the same resource and commit
IProject copy = checkoutCopy(project, "-copy");
addResources(copy, new String[] { "add1a.txt", "add1b.txt", "add2a.txt", "add2b.txt", "add3.txt"}, true);
deleteResources(copy, new String[] { "add3.txt"}, true);
// Get the sync tree for the project
assertSyncEquals("testAdditionConflicts", project,
new String[] { "file.txt", "add1a.txt", "add1b.txt", "add2a.txt", "add2b.txt", "add3.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.CONFLICTING | SyncInfo.ADDITION,
SyncInfo.CONFLICTING | SyncInfo.ADDITION,
SyncInfo.CONFLICTING | SyncInfo.ADDITION,
SyncInfo.CONFLICTING | SyncInfo.ADDITION,
SyncInfo.OUTGOING | SyncInfo.ADDITION });
// Commit conflicting add1b.txt and add2b.txt and outgoing add3.txt
overrideAndCommit(project, new String[]{"add1b.txt", "add2b.txt"}, true);
commit(project, new String[]{"add3.txt"});
assertSyncEquals("testAdditionConflicts", project,
new String[] { "file.txt", "add1b.txt", "add2b.txt", "add3.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC });
// Catch-up to conflicting cases using UPDATE
overrideAndUpdate(
project,
new String[] {"add1a.txt", "add2a.txt"},
true /* should prompt */);
assertSyncEquals("testAdditionConflicts", project,
new String[] { "add1a.txt", "add2a.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC });
}
/*
* Test conflicts involving deletions
*/
public void testDeletionConflicts() throws CoreException {
// CASE 1: The user deletes a remotely modified file
// (a) catch-up must do an update
// (b) release must do a merge
// CASE 2: The user deletes (and removes) a remotely modified file
// (a) catch-up must do an unmanage and update
// (b) release must do a merge
// CASE 3: The user modified a remotely deleted file
// (a) catch-up must do an unmanage and local delete
// (b) release must do a merge
// CASE 4: The user deletes a remotely deleted file
// (a) catch-up can update (or unmanage?)
// (b) release must unmanage
// CASE 5: The user deletes (and removes) a remotely deleted file
// (a) catch-up can update (or unmanage?)
// (b) release must unmanage
// Perform the test case for case A first
// Create a test project (which commits it as well) and delete the resource without committing
IProject project = createProject("testDeletionConflictsA", new String[] { "delete1.txt", "delete2.txt", "delete3.txt", "delete4.txt", "delete5.txt"});
IFile file = project.getFile("delete1.txt"); // WARNING: This does a "cvs remove"!!!
file.delete(false, DEFAULT_MONITOR);
deleteResources(project, new String[] {"delete2.txt"}, false);
setContentsAndEnsureModified(project.getFile("delete3.txt"));
file = project.getFile("delete4.txt");
file.delete(false, DEFAULT_MONITOR);
deleteResources(project, new String[] {"delete5.txt"}, false);
// Get the sync tree for the project
assertSyncEquals("testDeletionConflicts", project,
new String[] { "delete1.txt", "delete2.txt", "delete3.txt", "delete4.txt", "delete5.txt"},
true, new int[] {
SyncInfo.OUTGOING | SyncInfo.DELETION,
SyncInfo.OUTGOING | SyncInfo.DELETION,
SyncInfo.OUTGOING | SyncInfo.CHANGE,
SyncInfo.OUTGOING | SyncInfo.DELETION,
SyncInfo.OUTGOING | SyncInfo.DELETION });
// Checkout a copy and commit the deletion
IProject copy = checkoutCopy(project, "-copy");
setContentsAndEnsureModified(copy.getFile("delete1.txt"));
setContentsAndEnsureModified(copy.getFile("delete2.txt"));
deleteResources(copy, new String[] {"delete3.txt", "delete4.txt", "delete5.txt"}, false);
commitProject(copy);
// Get the sync tree for the project
assertSyncEquals("testDeletionConflictsA", project,
new String[] { "delete1.txt", "delete2.txt", "delete3.txt", "delete4.txt", "delete5.txt"},
true, new int[] {
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC });
// Catch up to remote changes.
overrideAndUpdate(
project,
new String[] {
"delete1.txt",
"delete2.txt",
"delete3.txt",
"delete4.txt",
"delete5.txt"},
true /* should be prompted */);
assertSyncEquals("testDeletionConflictsA", project,
new String[] { "delete1.txt", "delete2.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC });
assertDeleted("testDeletionConflictsA", project, new String[] {"delete3.txt", "delete4.txt", "delete5.txt"});
// Now redo the test case for case B
// Create a test project (which commits it as well) and delete the resource without committing
project = createProject("testDeletionConflictsB", new String[] { "delete1.txt", "delete2.txt", "delete3.txt", "delete4.txt", "delete5.txt"});
file = project.getFile("delete1.txt");
file.delete(false, DEFAULT_MONITOR);
deleteResources(project, new String[] {"delete2.txt"}, false);
setContentsAndEnsureModified(project.getFile("delete3.txt"));
file = project.getFile("delete4.txt");
file.delete(false, DEFAULT_MONITOR);
deleteResources(project, new String[] {"delete5.txt"}, false);
// Checkout a copy and commit the deletion
copy = checkoutCopy(project, "-copy");
setContentsAndEnsureModified(copy.getFile("delete1.txt"));
setContentsAndEnsureModified(copy.getFile("delete2.txt"));
deleteResources(copy, new String[] {"delete3.txt", "delete4.txt", "delete5.txt"}, false);
commitProject(copy);
// Get the sync tree for the project
assertSyncEquals("testDeletionConflictsB", project,
new String[] { "delete1.txt", "delete2.txt", "delete3.txt", "delete4.txt", "delete5.txt"},
true, new int[] {
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC });
// Release the resources
overrideAndCommit(project, new String[] { "delete1.txt", "delete2.txt", "delete3.txt"}, true);
commit(project, new String[] {"delete4.txt", "delete5.txt"});
assertSyncEquals("testDeletionConflictsB", project,
new String[] { "delete3.txt"},
true, new int[] {
SyncInfo.IN_SYNC });
assertDeleted("testDeletionConflictsB", project, new String[] {"delete1.txt", "delete2.txt", "delete4.txt", "delete5.txt"});
}
/*
* Test the creation and sync of an empty local project that has remote contents
*/
public void testSyncOnEmptyProject() throws TeamException, CoreException {
IProject project = createProject(new String[] { "file1.txt", "folder1/file2.txt"});
// Make a new folder and map it to the same project
IProject newProject = getUniqueTestProject("empty-" + getName());
FolderSyncInfo info = CVSWorkspaceRoot.getCVSFolderFor(project).getFolderSyncInfo();
CVSWorkspaceRoot.getCVSFolderFor(newProject).setFolderSyncInfo(info);
RepositoryProvider.map(newProject, CVSProviderPlugin.getTypeId());
// Assert that all resources are incoming additions
assertSyncEquals(newProject,
new String[] { "file1.txt", "folder1/", "folder1/file2.txt"},
true, new int[] {
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION});
}
/*
* Test a conflict with an incoming folder addition and an unmanaged local folder
*/
public void testFolderConflict() throws CoreException {
// Create a test project (which commits it as well) and delete the resource without committing
IProject project = createProject("testFolderConflict", new String[] { "file.txt"});
// Checkout a copy and add some folders
IProject copy = checkoutCopy(project, "-copy");
addResources(copy, new String[] {"folder1/file.txt", "folder2/file.txt"}, true);
// Add a folder to the original project (but not using cvs)
IResource[] resources = buildResources(project, new String[] {"folder1/"});
((IFolder)resources[0]).create(false, true, DEFAULT_MONITOR);
assertSyncEquals("testFolderConflict", project,
new String[] { "file.txt", "folder1/", "folder1/file.txt", "folder2/", "folder2/file.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.CONFLICTING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION});
update(
project,
new String[] {"folder1/"});
assertSyncEquals("testFolderConflict", project,
new String[] { "file.txt", "folder1/", "folder1/file.txt", "folder2/", "folder2/file.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION});
}
/*
* Test that a deleted file can still be deleted through the team provider
*/
public void testOutgoingDeletion() throws TeamException, CoreException {
// Create a test project (which commits it as well)
IProject project = createProject("testOutgoingDeletion", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Delete a file
IFile file = project.getFile("folder1/b.txt");
file.delete(true, DEFAULT_MONITOR); // WARNING: As of 2002/03/05, this is equivalent to a cvs remove
// Get the sync tree for the project
assertSyncEquals("testOutgoingDeletion", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.DELETION});
// Commit the deletion
commit(project , new String[] {"folder1/b.txt"});
// Get the sync tree again for the project and ensure others aren't effected
assertSyncEquals("testOutgoingDeletion", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC});
// Assert that deletion no longer appears in remote tree
assertDeleted("testOutgoingDeletion", project, new String[] {"folder1/b.txt"});
}
/*
* Test catching up to an incoming addition
*/
public void testIncomingAddition() throws CoreException {
// Create a test project
IProject project = createProject("testIncomingAddition", new String[] { "file1.txt", "folder1/", "folder1/a.txt"});
// Checkout and modify a copy
IProject copy = checkoutCopy(project, "-copy");
addResources(copy, new String[] { "folder1/add.txt" }, true);
// Get the sync tree for the project
assertSyncEquals("testIncomingAddition", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.INCOMING | SyncInfo.ADDITION});
// Catch up to the addition by updating
update(
project,
new String[] {"folder1/add.txt"});
// Get the sync tree again for the project and ensure the added resource is in sync
assertSyncEquals("testIncomingAddition", project,
new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC});
}
public void testSyncOnBranch() throws CoreException {
// Create a test project and a branch
IProject project = createProject(new String[] { "file1.txt", "file2.txt", "file3.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
CVSTag branch = new CVSTag("branch1", CVSTag.BRANCH);
tagProject(project, branch, false /* force */);
updateProject(project, branch, false);
// Checkout and modify a copy
IProject copy = checkoutCopy(project, branch);
addResources(copy, new String[] {"addition.txt", "folderAddition/", "folderAddition/new.txt"}, true);
deleteResources(copy, new String[] {"folder1/b.txt"}, true);
changeResources(copy, new String[] {"file1.txt", "file2.txt"}, true);
// Sync on the original and assert the result equals the copy
assertSyncEquals(project, new String[] {
"file1.txt",
"file2.txt",
"file3.txt",
"folder1/",
"folder1/a.txt",
"folder1/b.txt",
"addition.txt",
"folderAddition/",
"folderAddition/new.txt"},
true,
new int[] {
SyncInfo.INCOMING | SyncInfo.CHANGE,
SyncInfo.INCOMING | SyncInfo.CHANGE,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.INCOMING | SyncInfo.DELETION,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.INCOMING | SyncInfo.ADDITION});
}
public void testRenameProject() throws CoreException {
String[] resourceNames = new String[] { "changed.txt", "folder1/", "folder1/a.txt" };
int[] inSync = new int[] {SyncInfo.IN_SYNC, SyncInfo.IN_SYNC, SyncInfo.IN_SYNC};
IProject project = createProject("testRenameProject", new String[] { "changed.txt", "folder1/", "folder1/a.txt" });
assertSyncEquals("sync should be in sync", project, resourceNames, true, inSync);
IProjectDescription desc = project.getDescription();
String newName = project.getName() + "_renamed";
desc.setName(newName);
project.move(desc, false, null);
project = ResourcesPlugin.getWorkspace().getRoot().getProject(newName);
assertTrue(project.exists());
assertSyncEquals("sync should be in sync", project, resourceNames, true, inSync);
}
public void testDeleteProject() throws CoreException {
String[] resourceNames = new String[] { "deleted.txt", "file1.txt", "folder1/", "folder1/a.txt" };
int[] inSync = new int[] {SyncInfo.IN_SYNC, SyncInfo.IN_SYNC, SyncInfo.IN_SYNC, SyncInfo.IN_SYNC};
IProject project = createProject("testDeleteProject", resourceNames);
assertSyncEquals("sync should be in sync", project, resourceNames, true, inSync);
// Make some modifications
setContentsAndEnsureModified(project.getFile("folder1/a.txt"));
addResources(project, new String[] { "folder2/folder3/add.txt" }, false);
deleteResources(project, new String[] {"deleted.txt"}, false);
// Get the sync tree for the project
assertSyncEquals("testOutgoingChanges", project,
new String[] { "file1.txt", "folder1/", "deleted.txt", "folder1/a.txt", "folder2/", "folder2/folder3/", "folder2/folder3/add.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.DELETION,
SyncInfo.OUTGOING | SyncInfo.CHANGE,
SyncInfo.IN_SYNC, /* adding a folder creates it remotely */
SyncInfo.IN_SYNC, /* adding a folder creates it remotely */
SyncInfo.OUTGOING | SyncInfo.ADDITION});
project.delete(true, false, DEFAULT_MONITOR);
assertProjectRemoved(getWorkspaceSubscriber(), project);
}
public void testFolderDeletion() throws TeamException, CoreException {
IProject project = createProject("testFolderDeletion", new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt", "folder1/folder2/file.txt"});
// Delete a folder and ensure that the file is managed but doesn't exist
// (Special behavior is provider by the CVS move/delete hook but this is not part of CVS core)
project.getFolder("folder1").delete(false, false, null);
ICVSFolder folder = CVSWorkspaceRoot.getCVSFolderFor(project.getFolder("folder1"));
assertTrue("Deleted folder not in proper state", ! folder.exists() && folder.isManaged() && folder.isCVSFolder());
// The files should show up as outgoing deletions
assertSyncEquals("testFolderDeletion sync check", project,
new String[] { "folder1/", "folder1/a.txt", "folder1/folder2/", "folder1/folder2/file.txt"},
true, new int[] { SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.DELETION,
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.DELETION});
// commit folder1/a.txt
commit(project, new String[] { "folder1/a.txt" });
// Re-sync and verify that above file is gone and others remain the same
assertSyncEquals("testFolderDeletion sync check", project,
new String[] { "folder1/", "folder1/folder2/", "folder1/folder2/file.txt"},
true, new int[] { SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.DELETION});
assertDeleted("testFolderDeletion", project, new String[] {"folder1/a.txt"});
// Commit folder1/folder2/file.txt
commit(project, new String[] { "folder1/folder2/file.txt" });
// Re-sync and verify that all are deleted
assertDeleted("testFolderDeletion", project, new String[] {"folder1/", "folder1/folder2/", "folder1/folder2/file.txt"});
}
/**
* There is special handling required when building a sync tree for a tag when there are undiscovered folders
* that only contain other folders.
*/
public void testTagRetrievalForFolderWithNoFile() throws TeamException, CoreException {
IProject project = createProject("testTagRetrievalForFolderWithNoFile", new String[] { "changed.txt", "deleted.txt", "folder1/", "folder1/a.txt"});
// Checkout, branch and modify a copy
IProject copy = checkoutCopy(project, "-copy");
CVSTag version = new CVSTag("v1", CVSTag.BRANCH);
CVSTag branch = new CVSTag("branch1", CVSTag.BRANCH);
makeBranch(new IResource[] {copy}, version, branch, true);
addResources(copy, new String[] {"folder2/folder3/a.txt"}, true);
// Fetch the tree corresponding to the branch using the original as the base.
// XXX This will fail for CVSNT with directory pruning on
refresh(getSubscriber(), project);
}
public void testIgnoredResource() throws CoreException, TeamException {
// Create a test project (which commits it as well)
IProject project = createProject("testIgnoredResource", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Create a new file without adding it to version control
buildResources(project, new String[] {"ignored.txt"}, false);
// Get the sync tree for the project
assertSyncEquals("testIgnoredResource", project,
new String[] { "ignored.txt"},
true, new int[] {SyncInfo.OUTGOING | SyncInfo.ADDITION});
IFile ignores = project.getFile(".cvsignore");
ignores.create(new ByteArrayInputStream("ignored.txt".getBytes()), false, DEFAULT_MONITOR);
addResources(new IResource[] {ignores});
assertSyncEquals("testIgnoredResource", project,
new String[] { "ignored.txt", ".cvsignore"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.ADDITION});
}
public void testRenameUnshared() throws CoreException, TeamException {
// Create a test project (which commits it as well)
IProject project = createProject("testRenameUnshared", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Create a new file without adding it to version control
buildResources(project, new String[] {"oldName.txt"}, false);
// Get the sync tree for the project
assertSyncEquals("testRenameUnshared", project,
new String[] { "oldName.txt" },
true, new int[] {SyncInfo.OUTGOING | SyncInfo.ADDITION});
IFile rename = project.getFile("oldName.txt");
rename.move(new Path("newName.txt"), false, false, DEFAULT_MONITOR);
assertDeleted("testRenameUnshared", project, new String[] {"oldName.txt"});
assertSyncEquals("testRenameUnshared", project,
new String[] { "newName.txt"},
true, new int[] {
SyncInfo.OUTGOING | SyncInfo.ADDITION});
}
public void testOutgoingEmptyFolder() throws CoreException, TeamException {
// Create a test project (which commits it as well)
IProject project = createProject("testOutgoingEmptyFolder", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Create an empty folder without adding it to version control
buildResources(project, new String[] {"folder2/"}, false);
assertSyncEquals("testOutgoingEmptyFolder", project,
new String[] { "folder2/" },
true, new int[] {
SyncInfo.OUTGOING | SyncInfo.ADDITION});
commit(project, new String[] { "folder2" });
assertSyncEquals("testOutgoingEmptyFolder", project,
new String[] { "folder2/" },
true, new int[] {
SyncInfo.IN_SYNC});
// Ensure that the folder still exists (i.e. wasn't pruned)
assertTrue("Folder should still exist", project.getFolder("folder2").exists());
}
public void testDisconnectingProject() throws CoreException {
// Create a test project (which commits it as well)
IProject project = createProject("testDisconnect", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
RepositoryProvider.unmap(project);
assertProjectRemoved(getWorkspaceSubscriber(), project);
}
/*
* Test https://bugs.eclipse.org/bugs/show_bug.cgi?id=40221
*/
public void testConflictingFolderDeletion() throws CoreException {
// Create a test project (which commits it as well)
IProject project = createProject("testConflictingFolderDeletion", new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
// Checkout a copy
IProject copy = checkoutCopy(project, "-copy");
// Delete a folder in both projects and check-in one of the deletions
deleteResources(project, new String[] { "folder1/" }, false /* check-in */);
deleteResources(copy, new String[] { "folder1/" }, true /* check-in */);
// The files should show up as outgoing deletions
assertSyncEquals("testConflictingFolderDeletion sync check", project,
new String[] { "folder1/", "folder1/a.txt", "folder1/b.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC, /* conflicting deletions are handled automatically */
SyncInfo.IN_SYNC});
}
public void testOverrideAndUpdateOutgoingAddition() throws TeamException, CoreException {
// Create a test project (which commits it as well)
IProject project = createProject(new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
IFolder newFolder = project.getFolder("newFolder");
newFolder.create(false, true, null);
buildResources(newFolder, new String[] {"newFile"}, false);
overrideAndUpdate(project, new String[] {"newFolder", "newFolder/newFile"}, true);
assertDoesNotExistInFileSystem(newFolder);
}
public void testProjectClose() throws TeamException, CoreException {
IProject project = createProject(new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
setContentsAndEnsureModified(project.getFile("file1.txt"));
assertSyncEquals("testProjectClose sync check", project,
new String[] { "file1.txt"},
true, new int[] {
SyncInfo.OUTGOING | SyncInfo.CHANGE,
});
project.close(null);
assertProjectRemoved(getWorkspaceSubscriber(), project);
}
public void testUpdateBinaryConflict() throws CoreException{
// Create a shared project with a binary file
IProject project = createProject(new String[] { "binary.gif"});
assertIsBinary(project.getFile("binary.gif"));
// Checkout a copy, modify the binary file and commit
IProject copy = checkoutCopy(project, "-copy");
assertIsBinary(copy.getFile("binary.gif"));
setContentsAndEnsureModified(copy.getFile("binary.gif"));
commitProject(copy);
// Modify the same binary file and ensure sync is correct
setContentsAndEnsureModified(project.getFile("binary.gif"));
assertSyncEquals("testProjectClose sync check", project,
new String[] { "binary.gif"},
true, new int[] {
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
});
// Perform an update and ensure the binary conflict is skipped
update(project, new String[] { "binary.gif"});
assertSyncEquals("testProjectClose sync check", project,
new String[] { "binary.gif"},
true, new int[] {
SyncInfo.CONFLICTING | SyncInfo.CHANGE,
});
}
public void testNestedMarkAsMerged() throws CoreException, InvocationTargetException, InterruptedException {
if (TeamCVSTestPlugin.IS_UNSTABLE_TEST && Util.isMac())
return; //TODO Disable test for Mac because of intermittent test failures, see https://bugs.eclipse.org/408932
// Create a project and checkout a copy
IProject project = createProject(new String[] { "file1.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"});
IProject copy = checkoutCopy(project, "-copy");
// Add the same resources to both projects to create conflicting additions
buildResources(project, new String[] { "folder2/", "folder2/file.txt", "folder2/file2.txt"}, false);
addResources(copy, new String[] { "folder2/", "folder2/file.txt", "folder2/file2.txt"}, true);
assertSyncEquals("testNestedMarkAsMerged sync check", project,
new String[] { "folder2/", "folder2/file.txt", "folder2/file.txt"},
true, new int[] {
SyncInfo.CONFLICTING | SyncInfo.ADDITION,
SyncInfo.CONFLICTING | SyncInfo.ADDITION,
SyncInfo.CONFLICTING | SyncInfo.ADDITION
});
markAsMerged(getSubscriber(), project, new String[] {"folder2/file.txt"});
assertSyncEquals("testNestedMarkAsMerged sync check", project,
new String[] { "folder2/", "folder2/file.txt", "folder2/file2.txt"},
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.OUTGOING | SyncInfo.CHANGE,
SyncInfo.CONFLICTING | SyncInfo.ADDITION
});
}
public void testMarkAsMergedOnBinaryFile() throws TeamException, CoreException, InvocationTargetException, InterruptedException {
if (TeamCVSTestPlugin.IS_UNSTABLE_TEST && Util.isMac())
return; //TODO Disable test for Mac because of intermittent test failures, see https://bugs.eclipse.org/399509
// Create a project and checkout a copy
IProject project = createProject(new String[] { "file1.txt"});
IProject copy = checkoutCopy(project, "-copy");
// Add the same binary file to both projects to create a conflicting addition
buildResources(project, new String[] {"binary.gif"}, false);
addResources(copy, new String[] {"binary.gif"}, true);
assertIsBinary(copy.getFile("binary.gif"));
assertSyncEquals("testMarkAsMergedOnBinaryFile sync check", project,
new String[] {"binary.gif"},
true, new int[] {
SyncInfo.CONFLICTING | SyncInfo.ADDITION
});
markAsMerged(getSubscriber(), project, new String[] {"binary.gif"});
assertSyncEquals("testMarkAsMergedOnBinaryFile sync check", project,
new String[] {"binary.gif"},
true, new int[] {
SyncInfo.OUTGOING | SyncInfo.CHANGE
});
assertIsBinary(project.getFile("binary.gif"));
// Unmanage the file and do it again
// This tests the case were the contents are already cached locally
CVSWorkspaceRoot.getCVSFileFor(project.getFile("binary.gif")).unmanage(DEFAULT_MONITOR);
assertSyncEquals("testMarkAsMergedOnBinaryFile sync check", project,
new String[] {"binary.gif"},
true, new int[] {
SyncInfo.CONFLICTING | SyncInfo.ADDITION
});
markAsMerged(getSubscriber(), project, new String[] {"binary.gif"});
assertSyncEquals("testMarkAsMergedOnBinaryFile sync check", project,
new String[] {"binary.gif"},
true, new int[] {
SyncInfo.OUTGOING | SyncInfo.CHANGE
});
assertIsBinary(project.getFile("binary.gif"));
}
/**
* Bug 48467
*
* Files imported into CVS may have revision number 1.1.1.1.
* A subsequent commit will raise the revision to 1.2.
* We had code that would ignore the new sync bytes in the
* sync view because the new revision was shorter than the old one.
*/
public void testSyncAfterImport() throws CoreException {
// First, use "cvs import" to add a project to CVS
String[] resources = new String[] { "file.txt" };
IProject project = getUniqueTestProject(getName());
buildResources(project, resources, true);
importProject(project);
// Now, check out the project
IProject copy = getWorkspace().getRoot().getProject(project.getName() + "copy");
checkout(getRepository(), copy, project.getName(), null, DEFAULT_MONITOR);
ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(copy.getFile("file.txt"));
assertTrue("File in wrong state", cvsFile.isManaged() && cvsFile.getSyncInfo().getRevision().equals("1.1.1.1"));
// Check out another and commit a change to the file
IProject anotherCopy = checkoutCopy(copy, "another");
cvsFile = CVSWorkspaceRoot.getCVSFileFor(anotherCopy.getFile("file.txt"));
assertTrue("File in wrong state", cvsFile.isManaged() && cvsFile.getSyncInfo().getRevision().equals("1.1.1.1"));
setContentsAndEnsureModified(anotherCopy.getFile("file.txt"));
commitProject(anotherCopy);
// Assert that the change shows up in original
assertSyncEquals("testSyncAfterImport sync check", copy,
new String[] {"file.txt"},
true, new int[] {
SyncInfo.INCOMING | SyncInfo.CHANGE
});
}
public void testOverUpdateAfterExternalDeletion() throws TeamException, CoreException {
IProject project = createProject(new String[] { "file1.txt"});
int count = 0;
while (!project.getFile("file1.txt").getLocation().toFile().delete()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
assertTrue(count++ < 5);
}
project.refreshLocal(IResource.DEPTH_INFINITE, DEFAULT_MONITOR);
assertSyncEquals("testOverUpdateAfterExternalDeletion sync check", project,
new String[] {"file1.txt"},
true, new int[] {
SyncInfo.OUTGOING | SyncInfo.DELETION
});
overrideAndUpdate(project, new String[] { "file1.txt"}, true);
assertSyncEquals("testOverUpdateAfterExternalDeletion sync check", project,
new String[] {"file1.txt"},
true, new int[] {
SyncInfo.IN_SYNC
});
assertTrue(project.getFile("file1.txt").exists());
}
public void testBinaryAddition() throws CoreException {
// See bug 132255
KSubstOption option = CVSProviderPlugin.getPlugin().getDefaultTextKSubstOption();
try {
CVSProviderPlugin.getPlugin().setDefaultTextKSubstOption(Command.KSUBST_TEXT_KEYWORDS_ONLY);
IProject project = createProject(new String[] { "a.txt"});
// Checkout a copy
IProject copy = checkoutCopy(project, "-copy");
// Add a binary file that contains LFs
create(copy.getFile("binaryFile"), true);
setContentsAndEnsureModified(copy.getFile("binaryFile"), "/n/n\n\n");
addResources(new IResource[] { copy.getFile("binaryFile") });
commitProject(copy);
// Update
getSyncInfoSource().refresh(getSubscriber(), project);
getSyncInfoSource().updateResources(getSubscriber(), new IResource[] { project.getFile("binaryFile") });
assertContentsEqual(copy.getFile("binaryFile"), project.getFile("binaryFile"));
} finally {
CVSProviderPlugin.getPlugin().setDefaultTextKSubstOption(option);
}
}
public void testBinaryMarkAsMerged() throws CoreException, InvocationTargetException, InterruptedException {
KSubstOption option = CVSProviderPlugin.getPlugin().getDefaultTextKSubstOption();
try {
CVSProviderPlugin.getPlugin().setDefaultTextKSubstOption(Command.KSUBST_TEXT_KEYWORDS_ONLY);
IProject project = createProject(new String[] { "a.txt"});
// Checkout a copy
IProject copy = checkoutCopy(project, "-copy");
// Add a binary file to the copy and commit
create(copy.getFile("binaryFile"), true);
setContentsAndEnsureModified(copy.getFile("binaryFile"), "/n/n\n\n");
addResources(new IResource[] { copy.getFile("binaryFile") });
commitProject(copy);
// Add the same file to the project but don't share it
create(project.getFile("binaryFile"), true);
setContentsAndEnsureModified(project.getFile("binaryFile"), "/n/nSome Content\n\n");
// Sync and mark as merged
getSyncInfoSource().refresh(getSubscriber(), project);
getSyncInfoSource().markAsMerged(getSubscriber(), new IResource[] { project.getFile("binaryFile") });
assertIsBinary(project.getFile("binaryFile"));
} finally {
CVSProviderPlugin.getPlugin().setDefaultTextKSubstOption(option);
}
}
public void testDisabledDirectoryDiscovery() throws CoreException {
// Create a project and disable new directory discovery
IProject project = createProject(new String[] { "file1.txt"});
setFetchAbsentDirectories(project, false);
IProject copy = checkoutCopy(project, "-copy");
addResources(copy, new String[] { "added.txt", "folder2/", "folder2/added.txt" }, true);
// The new subfolder (folder2) and its contents should not have sync info (i.e. in_sync)
assertSyncEquals("testDisabledDirectoryDiscovery", project,
new String[] {"file1.txt", "added.txt", "folder2/", "folder2/added.txt" },
true, new int[] {
SyncInfo.IN_SYNC,
SyncInfo.INCOMING | SyncInfo.ADDITION,
SyncInfo.IN_SYNC,
SyncInfo.IN_SYNC
});
}
private void setFetchAbsentDirectories(IProject project, boolean fetch) throws CVSException {
RepositoryProvider provider = RepositoryProvider.getProvider(project, CVSProviderPlugin.getTypeId());
((CVSTeamProvider) provider).setFetchAbsentDirectories(fetch);
}
}