| /******************************************************************************* |
| * Copyright (c) 2000, 2017 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.util.*; |
| import java.util.List; |
| |
| import junit.framework.Test; |
| |
| import org.eclipse.compare.structuremergeviewer.IDiffElement; |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.swt.widgets.*; |
| import org.eclipse.team.core.TeamException; |
| import org.eclipse.team.core.diff.IDiff; |
| import org.eclipse.team.core.subscribers.Subscriber; |
| import org.eclipse.team.core.synchronize.SyncInfo; |
| import org.eclipse.team.internal.ccvs.core.CVSTag; |
| import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; |
| import org.eclipse.team.internal.core.subscribers.*; |
| import org.eclipse.team.internal.ui.synchronize.*; |
| import org.eclipse.team.tests.ccvs.ui.SubscriberParticipantSyncInfoSource; |
| import org.eclipse.team.ui.synchronize.*; |
| import org.eclipse.ui.PartInitException; |
| |
| /** |
| * Tests the change set mode of the synchronize view |
| */ |
| public class CVSChangeSetTests extends CVSSyncSubscriberTest { |
| |
| public static Test suite() { |
| return suite(CVSChangeSetTests.class); |
| } |
| |
| public CVSChangeSetTests() { |
| super(); |
| } |
| |
| public CVSChangeSetTests(String name) { |
| super(name); |
| } |
| |
| private void assertIncomingChangesInSets(IFile[][] files, String[] messages) throws CoreException { |
| // Get the workspace subscriber which also creates a participant and page in the sync view |
| Subscriber workspaceSubscriber = getWorkspaceSubscriber(); |
| refresh(workspaceSubscriber); |
| ISynchronizeModelElement root = getModelRoot(workspaceSubscriber); |
| ChangeSetDiffNode[] nodes = getCheckedInChangeSetNodes(root); |
| assertNodesInViewer(workspaceSubscriber, nodes); |
| assertEquals("The number of change sets in the sync view do not match the expected number", messages.length, nodes.length); |
| for (int i = 0; i < messages.length; i++) { |
| String message = messages[i]; |
| ChangeSetDiffNode node = getCommitSetFor(root, message); |
| assertNotNull("The commit set for '" + message + "' is not in the sync view", node); |
| List<IResource> filesInSet = new ArrayList<>(); |
| getFileChildren(node, filesInSet); |
| assertTrue("The number of files in the set do not match the expected number", files[i].length == filesInSet.size()); |
| for (int j = 0; j < files[i].length; j++) { |
| IFile file = files[i][j]; |
| assertTrue("File " + file.getFullPath() + " is not in the set", filesInSet.contains(file)); |
| } |
| } |
| } |
| |
| private void assertNodesInViewer(Subscriber workspaceSubscriber, ChangeSetDiffNode[] nodes) throws PartInitException { |
| ISynchronizeParticipant participant = SubscriberParticipantSyncInfoSource.getParticipant(workspaceSubscriber); |
| SubscriberParticipantPage page = (SubscriberParticipantPage)SubscriberParticipantSyncInfoSource.getSyncViewPage(participant); |
| TreeViewer viewer = (TreeViewer)page.getViewer(); |
| Tree tree = viewer.getTree(); |
| List<ChangeSetDiffNode> nodeList = new ArrayList<>(); |
| nodeList.addAll(Arrays.asList(nodes)); |
| TreeItem[] items = tree.getItems(); |
| removeTreeItemsFromList(nodeList, items); |
| assertTrue("Not all nodes are visible in the view", nodeList.isEmpty()); |
| } |
| |
| private void removeTreeItemsFromList(List<?> nodeList, TreeItem[] items) { |
| for (int i = 0; i < items.length; i++) { |
| TreeItem item = items[i]; |
| nodeList.remove(item.getData()); |
| TreeItem[] children = item.getItems(); |
| removeTreeItemsFromList(nodeList, children); |
| } |
| } |
| |
| private ChangeSetDiffNode[] getCheckedInChangeSetNodes(ISynchronizeModelElement root) { |
| List<ChangeSetDiffNode> result = new ArrayList<>(); |
| IDiffElement[] children = root.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| IDiffElement element = children[i]; |
| if (element instanceof ChangeSetDiffNode) { |
| ChangeSetDiffNode node = (ChangeSetDiffNode)element; |
| if (node.getSet() instanceof CheckedInChangeSet) { |
| result.add(node); |
| } |
| } |
| } |
| return result.toArray(new ChangeSetDiffNode[result.size()]); |
| } |
| |
| private ChangeSetDiffNode[] getActiveChangeSetNodes(ISynchronizeModelElement root) { |
| List<ChangeSetDiffNode> result = new ArrayList<>(); |
| IDiffElement[] children = root.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| IDiffElement element = children[i]; |
| if (element instanceof ChangeSetDiffNode) { |
| ChangeSetDiffNode node = (ChangeSetDiffNode)element; |
| if (node.getSet() instanceof ActiveChangeSet) { |
| result.add(node); |
| } |
| } |
| } |
| return result.toArray(new ChangeSetDiffNode[result.size()]); |
| } |
| |
| /** |
| * Adds IFiles to the list |
| */ |
| private void getFileChildren(ISynchronizeModelElement node, List<IResource> list) { |
| IResource resource = node.getResource(); |
| if (resource != null && resource.getType() == IResource.FILE) { |
| list.add(resource); |
| } |
| IDiffElement[] children = node.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| IDiffElement child = children[i]; |
| getFileChildren((ISynchronizeModelElement)child, list); |
| } |
| return; |
| } |
| |
| private ChangeSetDiffNode getCommitSetFor(ISynchronizeModelElement root, String message) { |
| IDiffElement[] children = root.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| IDiffElement element = children[i]; |
| if (element instanceof ChangeSetDiffNode) { |
| ChangeSetDiffNode node = (ChangeSetDiffNode)element; |
| if (node.getSet().getComment().equals(message)) { |
| return node; |
| } |
| } |
| } |
| return null; |
| } |
| |
| private void refresh(Subscriber workspaceSubscriber) throws TeamException { |
| workspaceSubscriber.refresh(workspaceSubscriber.roots(), IResource.DEPTH_INFINITE, DEFAULT_MONITOR); |
| } |
| |
| private void enableChangeSets(Subscriber workspaceSubscriber) throws PartInitException { |
| ISynchronizeParticipant participant = SubscriberParticipantSyncInfoSource.getParticipant(workspaceSubscriber); |
| SubscriberParticipantPage page = (SubscriberParticipantPage)SubscriberParticipantSyncInfoSource.getSyncViewPage(participant); |
| ChangeSetModelManager manager = (ChangeSetModelManager)page.getConfiguration().getProperty(SynchronizePageConfiguration.P_MODEL_MANAGER); |
| manager.setCommitSetsEnabled(true); |
| page.getConfiguration().setMode(ISynchronizePageConfiguration.BOTH_MODE); |
| } |
| |
| private void enableCheckedInChangeSets(Subscriber workspaceSubscriber) throws PartInitException { |
| enableChangeSets(workspaceSubscriber); |
| ISynchronizeParticipant participant = SubscriberParticipantSyncInfoSource.getParticipant(workspaceSubscriber); |
| SubscriberParticipantPage page = (SubscriberParticipantPage)SubscriberParticipantSyncInfoSource.getSyncViewPage(participant); |
| page.getConfiguration().setMode(ISynchronizePageConfiguration.INCOMING_MODE); |
| } |
| |
| private void enableActiveChangeSets(Subscriber workspaceSubscriber) throws PartInitException { |
| enableChangeSets(workspaceSubscriber); |
| ISynchronizeParticipant participant = SubscriberParticipantSyncInfoSource.getParticipant(workspaceSubscriber); |
| SubscriberParticipantPage page = (SubscriberParticipantPage)SubscriberParticipantSyncInfoSource.getSyncViewPage(participant); |
| page.getConfiguration().setMode(ISynchronizePageConfiguration.OUTGOING_MODE); |
| } |
| |
| /* |
| * Wait until all the background handlers have settled and then return the root element in the sync view |
| */ |
| private ISynchronizeModelElement getModelRoot(Subscriber workspaceSubscriber) throws CoreException { |
| IProgressMonitor eventLoopProgressMonitor = new IProgressMonitor() { |
| public void beginTask(String name, int totalWork) { |
| } |
| public void done() { |
| } |
| public void internalWorked(double work) { |
| } |
| public boolean isCanceled() { |
| return false; |
| } |
| public void setCanceled(boolean value) { |
| } |
| public void setTaskName(String name) { |
| } |
| public void subTask(String name) { |
| } |
| public void worked(int work) { |
| while (Display.getCurrent().readAndDispatch()) {} |
| } |
| }; |
| SubscriberParticipantSyncInfoSource.getCollector(workspaceSubscriber); |
| ISynchronizeParticipant participant = SubscriberParticipantSyncInfoSource.getParticipant(workspaceSubscriber); |
| ChangeSetCapability capability = ((IChangeSetProvider)participant).getChangeSetCapability(); |
| SubscriberChangeSetManager activeManager = (SubscriberChangeSetManager)capability.getActiveChangeSetManager(); |
| activeManager.waitUntilDone(eventLoopProgressMonitor); |
| SubscriberParticipantPage page = (SubscriberParticipantPage)SubscriberParticipantSyncInfoSource.getSyncViewPage(participant); |
| ChangeSetModelManager manager = (ChangeSetModelManager)page.getConfiguration().getProperty(SynchronizePageConfiguration.P_MODEL_MANAGER); |
| AbstractSynchronizeModelProvider provider = (AbstractSynchronizeModelProvider)manager.getActiveModelProvider(); |
| provider.waitUntilDone(eventLoopProgressMonitor); |
| return provider.getModelRoot(); |
| } |
| |
| private ActiveChangeSetManager getActiveChangeSetManager() { |
| return CVSUIPlugin.getPlugin().getChangeSetManager(); |
| } |
| |
| /* |
| * Assert that the given resources make up the given set both directly |
| * and by what is displayed in the sync view. |
| */ |
| private void assertInActiveSet(IResource[] resources, ActiveChangeSet set) throws CoreException { |
| assertResourcesAreTheSame(resources, set.getResources(), true); |
| ISynchronizeModelElement root = getModelRoot(((SubscriberChangeSetManager)getActiveChangeSetManager()).getSubscriber()); |
| ChangeSetDiffNode node = getChangeSetNodeFor(root, set); |
| assertNotNull("Change set " + set.getTitle() + " did not appear in the sync view", node); |
| IResource[] outOfSync = getOutOfSyncResources(node); |
| assertResourcesAreTheSame(resources, outOfSync, true); |
| // Assert that all active sets are visible in the view |
| ChangeSet[] sets = getActiveChangeSetManager().getSets(); |
| for (int i = 0; i < sets.length; i++) { |
| ChangeSet changeSet = sets[i]; |
| node = getChangeSetNodeFor(root, changeSet); |
| assertNotNull("The node for set " + set.getName() + " is not in the view", node); |
| |
| } |
| ChangeSetDiffNode[] nodes = getActiveChangeSetNodes(root); |
| assertNodesInViewer(getWorkspaceSubscriber(), nodes); |
| } |
| |
| private ChangeSetDiffNode getChangeSetNodeFor(ISynchronizeModelElement root, ChangeSet set) { |
| IDiffElement[] children = root.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| IDiffElement element = children[i]; |
| if (element instanceof ChangeSetDiffNode) { |
| ChangeSetDiffNode node = (ChangeSetDiffNode)element; |
| if (node.getSet() == set) { |
| return node; |
| } |
| } |
| } |
| return null; |
| } |
| |
| private IResource[] getOutOfSyncResources(ISynchronizeModelElement element) { |
| ArrayList<SyncInfo> arrayList = new ArrayList<>(); |
| getOutOfSync(element, arrayList); |
| SyncInfo[] infos = arrayList.toArray(new SyncInfo[arrayList.size()]); |
| IResource[] resources = getResources(infos); |
| return resources; |
| } |
| |
| private IResource[] getResources(SyncInfo[] infos) { |
| IResource[] resources = new IResource[infos.length]; |
| for (int i = 0; i < resources.length; i++) { |
| resources[i] = infos[i].getLocal(); |
| } |
| return resources; |
| } |
| |
| private void getOutOfSync(ISynchronizeModelElement node, List<SyncInfo> list) { |
| SyncInfo info = getSyncInfo(node); |
| if (info != null && info.getKind() != SyncInfo.IN_SYNC) { |
| list.add(info); |
| } |
| IDiffElement[] children = node.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| IDiffElement child = children[i]; |
| getOutOfSync((ISynchronizeModelElement)child, list); |
| } |
| return; |
| } |
| |
| private SyncInfo getSyncInfo(ISynchronizeModelElement node) { |
| if (node instanceof IAdaptable) { |
| return ((IAdaptable)node).getAdapter(SyncInfo.class); |
| } |
| return null; |
| } |
| |
| private void assertResourcesAreTheSame(IResource[] resources1, IResource[] resources2, boolean doNotAllowExtra) { |
| if (doNotAllowExtra) { |
| if (resources1.length != resources2.length) { |
| System.out.println("Expected"); |
| for (int i = 0; i < resources1.length; i++) { |
| IResource resource = resources1[i]; |
| System.out.println(resource.getFullPath().toString()); |
| } |
| System.out.println("Actual"); |
| for (int i = 0; i < resources2.length; i++) { |
| IResource resource = resources2[i]; |
| System.out.println(resource.getFullPath().toString()); |
| } |
| } |
| assertEquals("The number of resources do not match the expected number", resources1.length, resources2.length); |
| } |
| for (int i = 0; i < resources1.length; i++) { |
| IResource resource = resources1[i]; |
| boolean found = false; |
| for (int j = 0; j < resources2.length; j++) { |
| IResource resource2 = resources2[j]; |
| if (resource2.equals(resource)) { |
| found = true; |
| break; |
| } |
| } |
| assertTrue("Expected resource " + resource.getFullPath().toString() + " was not present", found); |
| } |
| } |
| |
| /* |
| * Assert that the given resources make up the root set |
| * displayed in the sync view. The root set is those |
| * resources that are not part of an active change set. |
| */ |
| private void assertInRootSet(IResource[] resources) throws CoreException { |
| ISynchronizeModelElement[] nodes = getNonChangeSetRoots(getModelRoot(((SubscriberChangeSetManager)getActiveChangeSetManager()).getSubscriber())); |
| List<SyncInfo> list = new ArrayList<>(); |
| for (int i = 0; i < nodes.length; i++) { |
| ISynchronizeModelElement element = nodes[i]; |
| getOutOfSync(element, list); |
| } |
| IResource[] outOfSync = getResources(list.toArray(new SyncInfo[list.size()])); |
| // Only require that the expected resources are there but allow extra. |
| // This is required because of junk left over from previous tests. |
| // This means there is a bug somewhere. But where? |
| assertResourcesAreTheSame(resources, outOfSync, false /* allow extra out-of-sync resources */); |
| |
| } |
| |
| private ISynchronizeModelElement[] getNonChangeSetRoots(ISynchronizeModelElement modelRoot) { |
| List<ISynchronizeModelElement> result = new ArrayList<>(); |
| IDiffElement[] children = modelRoot.getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| IDiffElement element = children[i]; |
| if (!(element instanceof ChangeSetDiffNode)) { |
| result.add((ISynchronizeModelElement) element); |
| } |
| } |
| return result.toArray(new ISynchronizeModelElement[result.size()]); |
| } |
| |
| public void testSimpleCommit() throws CoreException { |
| enableCheckedInChangeSets(getWorkspaceSubscriber()); |
| |
| IProject project = createProject(new String[] { "file1.txt", "file2.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"}); |
| |
| // Modify a file in a copy |
| IProject copy = checkoutCopy(project, CVSTag.DEFAULT); |
| setContentsAndEnsureModified(copy.getFile("file1.txt")); |
| String message1 = "Commit 1"; |
| commitResources(new IResource[] {copy}, IResource.DEPTH_INFINITE, message1); |
| assertIncomingChangesInSets(new IFile[][] {{ project.getFile("file1.txt") }}, new String[] {message1}); |
| |
| // Modify the copy some more |
| setContentsAndEnsureModified(copy.getFile("file2.txt")); |
| setContentsAndEnsureModified(copy.getFile("folder1/a.txt")); |
| String message2 = "Commit 2"; |
| commitResources(new IResource[] {copy}, IResource.DEPTH_INFINITE, message2); |
| assertIncomingChangesInSets(new IFile[][] { |
| { project.getFile("file1.txt") }, |
| { project.getFile("file2.txt"), project.getFile("folder1/a.txt") } |
| }, new String[] {message1, message2}); |
| |
| // Modify the copy some more |
| setContentsAndEnsureModified(copy.getFile("file2.txt")); |
| String message3 = "Commit 3"; |
| commitResources(new IResource[] {copy}, IResource.DEPTH_INFINITE, message3); |
| assertIncomingChangesInSets(new IFile[][] { |
| { project.getFile("file1.txt") }, |
| { project.getFile("folder1/a.txt") }, |
| { project.getFile("file2.txt")} |
| }, new String[] {message1, message2, message3}); |
| |
| // Now commit the files in one of the sets and ensure it is removed from the view |
| updateResources(new IResource[] { project.getFile("file1.txt")}, false); |
| assertIncomingChangesInSets(new IFile[][] { |
| { project.getFile("folder1/a.txt") }, |
| { project.getFile("file2.txt")} |
| }, new String[] {message2, message3}); |
| } |
| |
| public void testSimpleActiveChangeSet() throws CoreException { |
| IProject project = createProject(new String[] { "file1.txt", "file2.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"}); |
| // Enable Change Sets |
| enableActiveChangeSets(getWorkspaceSubscriber()); |
| // Add a folder and file |
| IFolder newFolder = project.getFolder("folder2"); |
| newFolder.create(false, true, null); |
| IFile newFile = newFolder.getFile("file.txt"); |
| newFile.create(new ByteArrayInputStream("Hi There".getBytes()), false, null); |
| // Create an active commit set and assert that it appears in the sync view |
| ActiveChangeSetManager manager = getActiveChangeSetManager(); |
| ActiveChangeSet set = manager.createSet("test", new IDiff[0]); |
| manager.add(set); |
| assertInActiveSet(new IResource[] { }, set); |
| assertInRootSet(new IResource[] {newFolder, newFile}); |
| // Add the new file to the set and assert that the file is in the set and the folder is still at the root |
| set.add(new IResource[] { newFile }); |
| assertInActiveSet(new IResource[] { newFile }, set); |
| assertInRootSet(new IResource[] {newFolder }); |
| // Add the folder to the set |
| set.add(new IResource[] { newFolder }); |
| assertInActiveSet(new IResource[] { newFolder, newFile }, set); |
| } |
| } |