| /******************************************************************************* |
| * Copyright (c) 2000, 2015 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 |
| * Alexander Kurtakov <akurtako@redhat.com> - Bug 459343 |
| *******************************************************************************/ |
| package org.eclipse.core.tests.resources; |
| |
| import java.util.*; |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.runtime.*; |
| import org.junit.Assert; |
| |
| /** |
| * Verifies the state of an <code>IResourceDelta</code> by comparing |
| * it with a client's expectations. The delta is considered valid |
| * if it contains exactly the set of changes expected by the client, |
| * and parents of those changes. |
| * |
| * <p>Example usage: |
| * <code> |
| * ResourceDeltaVerifier verifier = new ResourceDeltaComparer(); |
| * IResourceChangeListener listener = (IResourceChangeListener)verifier; |
| * IWorkspace workspace = ResourcesPlugin.getWorkspace(); |
| * IProject proj = workspace.getRoot().getProject("MyProject"); |
| * // Assume the project is accessible |
| * workspace.addResourceChangeListener(listener); |
| * verifier.addExpectedChange(proj, REMOVED, 0); |
| * try { |
| * proj.delete(true, true, null); |
| * } catch(CoreException e){ |
| * fail("1.0", e); |
| * } |
| * assert("2.0 "+verifier.getMessage(), verifier.isDeltaValid()); |
| * </code> |
| */ |
| public class ResourceDeltaVerifier extends Assert implements IResourceChangeListener { |
| private class ExpectedChange { |
| IResource fResource; |
| IPath movedFromPath; |
| IPath movedToPath; |
| int fKind; |
| int fChangeFlags; |
| |
| public ExpectedChange(IResource resource, int kind, int changeFlags, IPath movedFromPath, IPath movedToPath) { |
| fResource = resource; |
| fKind = kind; |
| fChangeFlags = changeFlags; |
| this.movedFromPath = movedFromPath; |
| this.movedToPath = movedToPath; |
| } |
| |
| public int getChangeFlags() { |
| return fChangeFlags; |
| } |
| |
| public IPath getMovedFromPath() { |
| if ((fChangeFlags & IResourceDelta.MOVED_FROM) != 0) { |
| return movedFromPath; |
| } |
| return null; |
| } |
| |
| public IPath getMovedToPath() { |
| if ((fChangeFlags & IResourceDelta.MOVED_TO) != 0) { |
| return movedToPath; |
| } |
| return null; |
| } |
| |
| public int getKind() { |
| return fKind; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder buf = new StringBuilder("ExpectedChange("); |
| buf.append(fResource); |
| buf.append(", "); |
| buf.append(convertKind(fKind)); |
| buf.append(", "); |
| buf.append(convertChangeFlags(fChangeFlags)); |
| buf.append(")"); |
| return buf.toString(); |
| } |
| |
| } |
| |
| /** |
| * Table of IPath -> ExpectedChange |
| */ |
| private Hashtable<IPath, ExpectedChange> fExpectedChanges = new Hashtable<>(); |
| boolean fIsDeltaValid = true; |
| private StringBuilder fMessage = new StringBuilder(); |
| /** |
| * The verifier can be in one of three states. In the initial |
| * state, the verifier is still receiving inputs via the |
| * addExpectedChange() methods, and the state is RECEIVING_INPUTS. |
| * After a call to verifyDelta(), the state becomes DELTA_VERIFIED |
| * The verifier remains in the second state for any number of delta |
| * verifications. When a getMessage() or isDeltaValid() method is |
| * called, the verification completes, and the state becomes |
| * VERIFICATION_COMPLETE. While in this state, any number of |
| * getMessage() and isDeltaValid() methods can be called. |
| * While in the third state, any call to addExpectedChange() |
| * resets the verifier and puts it back in its RECEIVING_INPUTS state. |
| */ |
| private static final int RECEIVING_INPUTS = 0; |
| private static final int DELTA_VERIFIED = 1; |
| private static final int VERIFICATION_COMPLETE = 2; |
| |
| private int fState = RECEIVING_INPUTS; |
| |
| /** |
| * @see #addExpectedChange |
| */ |
| public void addExpectedChange(IResource[] resources, int status, int changeFlags) { |
| for (IResource resource : resources) { |
| addExpectedChange(resource, null, status, changeFlags, null, null); |
| } |
| } |
| |
| /** |
| * Adds an expected deletion for the given resource and all children. |
| */ |
| public void addExpectedDeletion(IResource resource) { |
| addExpectedChange(resource, IResourceDelta.REMOVED, 0); |
| if (resource instanceof IContainer) { |
| try { |
| IResource[] children = ((IContainer) resource).members(IContainer.INCLUDE_PHANTOMS | IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
| for (IResource element : children) { |
| addExpectedDeletion(element); |
| } |
| } catch (CoreException e) { |
| e.printStackTrace(); |
| fail("Failed to get children in addExpectedDeletion"); |
| } |
| } |
| } |
| |
| /** |
| * Signals to the comparer that the given resource is expected to |
| * change in the specified way. The change flags should be set to |
| * zero if no change is expected. |
| * @param resource the resource that is expected to change |
| * @param status the type of change (ADDED, REMOVED, CHANGED) |
| * @param changeFlags the type of change (CONTENT, SYNC, etc) |
| * @see IResourceConstants |
| */ |
| public void addExpectedChange(IResource resource, int status, int changeFlags) { |
| addExpectedChange(resource, null, status, changeFlags, null, null); |
| } |
| |
| /** |
| * Signals to the comparer that the given resource is expected to |
| * change in the specified way. The change flags should be set to |
| * zero if no change is expected. |
| * @param resource the resource that is expected to change |
| * @param status the type of change (ADDED, REMOVED, CHANGED) |
| * @param changeFlags the type of change (CONTENT, SYNC, etc) |
| * @param movedPath or null |
| * @see IResourceConstants |
| */ |
| public void addExpectedChange(IResource resource, int status, int changeFlags, IPath movedFromPath, IPath movedToPath) { |
| addExpectedChange(resource, null, status, changeFlags, movedFromPath, movedToPath); |
| } |
| |
| /** |
| * Signals to the comparer that the given resource is expected to |
| * change in the specified way. The change flags should be set to |
| * zero if no change is expected. |
| * @param resource the resource that is expected to change |
| * @param topLevelParent Do not added expected changes above this parent |
| * @param status the type of change (ADDED, REMOVED, CHANGED) |
| * @param changeFlags the type of change (CONTENT, SYNC, etc) |
| * @param movedPath or null |
| * @see IResourceConstants |
| */ |
| public void addExpectedChange(IResource resource, IResource topLevelParent, int status, int changeFlags) { |
| addExpectedChange(resource, topLevelParent, status, changeFlags, null, null); |
| } |
| |
| /** |
| * Signals to the comparer that the given resource is expected to |
| * change in the specified way. The change flags should be set to |
| * zero if no change is expected. |
| * @param resource the resource that is expected to change |
| * @param topLevelParent Do not added expected changes above this parent |
| * @param status the type of change (ADDED, REMOVED, CHANGED) |
| * @param changeFlags the type of change (CONTENT, SYNC, etc) |
| * @param movedPath or null |
| * @see IResourceConstants |
| */ |
| public void addExpectedChange(IResource resource, IResource topLevelParent, int status, int changeFlags, IPath movedFromPath, IPath movedToPath) { |
| resetIfNecessary(); |
| |
| ExpectedChange expectedChange = new ExpectedChange(resource, status, changeFlags, movedFromPath, movedToPath); |
| fExpectedChanges.put(resource.getFullPath(), expectedChange); |
| |
| // Add changes for all resources above this one and limited by the topLevelParent |
| IResource parentResource = resource.getParent(); |
| IResource limit = (topLevelParent == null) ? null : topLevelParent.getParent(); |
| while (parentResource != null && !parentResource.equals(limit)) { |
| //change table is keyed by resource path |
| IPath key = parentResource.getFullPath(); |
| if (fExpectedChanges.get(key) == null) { |
| ExpectedChange parentExpectedChange = new ExpectedChange(parentResource, IResourceDelta.CHANGED, 0, null, null); |
| fExpectedChanges.put(key, parentExpectedChange); |
| } |
| parentResource = parentResource.getParent(); |
| } |
| } |
| |
| private void checkChanges(IResourceDelta delta) { |
| IResource resource = delta.getResource(); |
| |
| ExpectedChange expectedChange = fExpectedChanges.remove(resource.getFullPath()); |
| |
| int status = delta.getKind(); |
| int changeFlags = delta.getFlags(); |
| |
| if (status == IResourceDelta.NO_CHANGE) { |
| return; |
| } |
| |
| if (expectedChange == null) { |
| recordMissingExpectedChange(status, changeFlags); |
| } else { |
| int expectedStatus = expectedChange.getKind(); |
| int expectedChangeFlags = expectedChange.getChangeFlags(); |
| if (status != expectedStatus || changeFlags != expectedChangeFlags) { |
| recordConflictingChange(expectedStatus, status, expectedChangeFlags, changeFlags); |
| } |
| } |
| } |
| |
| private void checkChildren(IResourceDelta delta) { |
| IResourceDelta[] affectedChildren = delta.getAffectedChildren(IResourceDelta.ALL_WITH_PHANTOMS, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
| IResourceDelta[] addedChildren = delta.getAffectedChildren(IResourceDelta.ADDED, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
| IResourceDelta[] changedChildren = delta.getAffectedChildren(IResourceDelta.CHANGED, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
| IResourceDelta[] removedChildren = delta.getAffectedChildren(IResourceDelta.REMOVED, IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
| |
| Hashtable<IResource, IResourceDelta> h = new Hashtable<>(affectedChildren.length + 1); |
| |
| for (IResourceDelta childDelta1 : addedChildren) { |
| IResource childResource = childDelta1.getResource(); |
| IResourceDelta childDelta2 = h.get(childResource); |
| if (childDelta2 != null) { |
| recordDuplicateChild(childResource.getFullPath(), childDelta2.getKind(), childDelta1.getKind(), IResourceDelta.ADDED); |
| } else { |
| h.put(childResource, childDelta1); |
| } |
| if (childDelta1.getKind() != IResourceDelta.ADDED) { |
| recordIllegalChild(childResource.getFullPath(), IResourceDelta.ADDED, childDelta1.getKind()); |
| } |
| } |
| |
| for (IResourceDelta childDelta1 : changedChildren) { |
| IResource childResource = childDelta1.getResource(); |
| IResourceDelta childDelta2 = h.get(childResource); |
| if (childDelta2 != null) { |
| recordDuplicateChild(childResource.getFullPath(), childDelta2.getKind(), childDelta1.getKind(), IResourceDelta.CHANGED); |
| } else { |
| h.put(childResource, childDelta1); |
| } |
| if (childDelta1.getKind() != IResourceDelta.CHANGED) { |
| recordIllegalChild(childResource.getFullPath(), IResourceDelta.CHANGED, childDelta1.getKind()); |
| } |
| } |
| |
| for (IResourceDelta childDelta1 : removedChildren) { |
| IResource childResource = childDelta1.getResource(); |
| IResourceDelta childDelta2 = h.get(childResource); |
| if (childDelta2 != null) { |
| recordDuplicateChild(childResource.getFullPath(), childDelta2.getKind(), childDelta1.getKind(), IResourceDelta.REMOVED); |
| } else { |
| h.put(childResource, childDelta1); |
| } |
| if (childDelta1.getKind() != IResourceDelta.REMOVED) { |
| recordIllegalChild(childResource.getFullPath(), IResourceDelta.REMOVED, childDelta1.getKind()); |
| } |
| } |
| |
| for (IResourceDelta childDelta1 : affectedChildren) { |
| IResource childResource = childDelta1.getResource(); |
| IResourceDelta childDelta2 = h.remove(childResource); |
| if (childDelta2 == null) { |
| int kind = childDelta1.getKind(); |
| //these kinds should have been added to h earlier |
| if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED || kind == IResourceDelta.CHANGED) { |
| recordMissingChild(childResource.getFullPath(), childDelta1.getKind(), false); |
| } |
| } |
| } |
| |
| for (Map.Entry<IResource, IResourceDelta> entry : h.entrySet()) { |
| IResource childResource = entry.getKey(); |
| IResourceDelta childDelta = entry.getValue(); |
| recordMissingChild(childResource.getFullPath(), childDelta.getKind(), true); |
| } |
| |
| for (IResourceDelta element : affectedChildren) { |
| internalVerifyDelta(element); |
| } |
| |
| for (IResourceDelta childDelta : h.values()) { |
| internalVerifyDelta(childDelta); |
| } |
| } |
| |
| private void checkPaths(IResourceDelta delta) { |
| IResource resource = delta.getResource(); |
| |
| IPath expectedFullPath = resource.getFullPath(); |
| IPath actualFullPath = delta.getFullPath(); |
| if (!expectedFullPath.equals(actualFullPath)) { |
| recordConflictingFullPaths(expectedFullPath, actualFullPath); |
| } |
| |
| IPath expectedProjectRelativePath = resource.getProjectRelativePath(); |
| IPath actualProjectRelativePath = delta.getProjectRelativePath(); |
| if (expectedProjectRelativePath != actualProjectRelativePath) { |
| if (expectedProjectRelativePath == null || !expectedProjectRelativePath.equals(actualProjectRelativePath)) { |
| recordConflictingProjectRelativePaths(expectedProjectRelativePath, actualProjectRelativePath); |
| } |
| } |
| |
| ExpectedChange expectedChange = fExpectedChanges.get(resource.getFullPath()); |
| |
| if (expectedChange != null) { |
| IPath expectedMovedFromPath = expectedChange.getMovedFromPath(); |
| IPath actualMovedFromPath = delta.getMovedFromPath(); |
| if (expectedMovedFromPath != actualMovedFromPath) { |
| if (expectedMovedFromPath == null || !expectedMovedFromPath.equals(actualMovedFromPath)) { |
| recordConflictingMovedFromPaths(expectedMovedFromPath, actualMovedFromPath); |
| } |
| } |
| |
| IPath expectedMovedToPath = expectedChange.getMovedToPath(); |
| IPath actualMovedToPath = delta.getMovedToPath(); |
| if (expectedMovedToPath != actualMovedToPath) { |
| if (expectedMovedToPath == null || !expectedMovedToPath.equals(actualMovedToPath)) { |
| recordConflictingMovedToPaths(expectedMovedToPath, actualMovedToPath); |
| } |
| } |
| } |
| } |
| |
| String convertChangeFlags(int changeFlags) { |
| if (changeFlags == 0) { |
| return "0"; |
| } |
| StringBuilder buf = new StringBuilder(); |
| |
| if ((changeFlags & IResourceDelta.CONTENT) != 0) { |
| changeFlags ^= IResourceDelta.CONTENT; |
| buf.append("CONTENT | "); |
| } |
| if ((changeFlags & IResourceDelta.MOVED_FROM) != 0) { |
| changeFlags ^= IResourceDelta.MOVED_FROM; |
| buf.append("MOVED_FROM | "); |
| } |
| if ((changeFlags & IResourceDelta.MOVED_TO) != 0) { |
| changeFlags ^= IResourceDelta.MOVED_TO; |
| buf.append("MOVED_TO | "); |
| } |
| if ((changeFlags & IResourceDelta.OPEN) != 0) { |
| changeFlags ^= IResourceDelta.OPEN; |
| buf.append("OPEN | "); |
| } |
| if ((changeFlags & IResourceDelta.TYPE) != 0) { |
| changeFlags ^= IResourceDelta.TYPE; |
| buf.append("TYPE | "); |
| } |
| if ((changeFlags & IResourceDelta.MARKERS) != 0) { |
| changeFlags ^= IResourceDelta.MARKERS; |
| buf.append("MARKERS | "); |
| } |
| if ((changeFlags & IResourceDelta.REPLACED) != 0) { |
| changeFlags ^= IResourceDelta.REPLACED; |
| buf.append("REPLACED | "); |
| } |
| if ((changeFlags & IResourceDelta.ENCODING) != 0) { |
| changeFlags ^= IResourceDelta.ENCODING; |
| buf.append("ENCODING | "); |
| } |
| if ((changeFlags & IResourceDelta.DERIVED_CHANGED) != 0) { |
| changeFlags ^= IResourceDelta.DERIVED_CHANGED; |
| buf.append("DERIVED_CHANGED | "); |
| } |
| if ((changeFlags & IResourceDelta.DESCRIPTION) != 0) { |
| changeFlags ^= IResourceDelta.DESCRIPTION; |
| buf.append("DESCRIPTION | "); |
| } |
| if ((changeFlags & IResourceDelta.SYNC) != 0) { |
| changeFlags ^= IResourceDelta.SYNC; |
| buf.append("SYNC | "); |
| } |
| |
| if (changeFlags != 0) { |
| buf.append(changeFlags); |
| buf.append(" | "); |
| } |
| |
| String result = buf.toString(); |
| |
| if (result.length() != 0) { |
| result = result.substring(0, result.length() - 3); |
| } |
| |
| return result; |
| } |
| |
| String convertKind(int kind) { |
| switch (kind) { |
| case IResourceDelta.ADDED : |
| return "ADDED"; |
| case IResourceDelta.CHANGED : |
| return "CHANGED"; |
| case IResourceDelta.REMOVED : |
| return "REMOVED"; |
| case IResourceDelta.ADDED_PHANTOM : |
| return "ADDED_PHANTOM"; |
| case IResourceDelta.REMOVED_PHANTOM : |
| return "REMOVED_PHANTOM"; |
| default : |
| return "Unknown(" + kind + ")"; |
| } |
| } |
| |
| /** |
| * Called to cleanup internal state and make sure expectations |
| * are met after iterating over a resource delta. |
| */ |
| private void finishVerification() { |
| HashSet<IPath> resourcePaths = new HashSet<>(fExpectedChanges.keySet()); |
| |
| for (IPath resourcePath : resourcePaths) { |
| fMessage.append("Checking expectations for "); |
| fMessage.append(resourcePath); |
| fMessage.append("\n"); |
| |
| ExpectedChange expectedChange = fExpectedChanges.remove(resourcePath); |
| if (expectedChange != null) { |
| recordMissingActualChange(expectedChange.getKind(), expectedChange.getChangeFlags()); |
| } |
| } |
| } |
| |
| /** |
| * Returns a message that describes the result of the resource |
| * delta verification checks. |
| */ |
| public String getMessage() { |
| if (fState == RECEIVING_INPUTS) { |
| if (hasExpectedChanges()) { |
| fail("Verifier has not yet been given a resource delta"); |
| } else { |
| fState = DELTA_VERIFIED; |
| } |
| } |
| if (fState == DELTA_VERIFIED) { |
| finishVerification(); |
| fState = VERIFICATION_COMPLETE; |
| } |
| return fMessage.toString(); |
| } |
| |
| /** |
| * Returns true if this verifier has received a delta notification |
| * since the last reset, and false otherwise. |
| */ |
| public boolean hasBeenNotified() { |
| return fState == DELTA_VERIFIED; |
| } |
| |
| /** |
| * Returns true if this verifier currently has an expected |
| * changes, and false otherwise. |
| */ |
| public boolean hasExpectedChanges() { |
| return !fExpectedChanges.isEmpty(); |
| } |
| |
| /** |
| * Compares the given delta with the expected changes. Recursively |
| * compares child deltas. |
| */ |
| void internalVerifyDelta(IResourceDelta delta) { |
| try { |
| // FIXME: bogus |
| if (delta == null) { |
| return; |
| } |
| fMessage.append("Verifying delta for "); |
| fMessage.append(delta.getFullPath()); |
| fMessage.append("\n"); |
| |
| /* don't check changes for the workspace */ |
| if (delta.getResource() != null) { |
| checkPaths(delta); |
| checkChanges(delta); |
| } |
| checkChildren(delta); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| fMessage.append("Exception during event notification:" + e.getMessage()); |
| fIsDeltaValid = false; |
| } |
| } |
| |
| /** |
| * Returns whether the resource delta passed all verification |
| * checks. |
| */ |
| public boolean isDeltaValid() { |
| if (fState == RECEIVING_INPUTS) { |
| if (hasExpectedChanges()) { |
| fail("Verifier has not yet been given a resource delta"); |
| } else { |
| fState = DELTA_VERIFIED; |
| } |
| } |
| if (fState == DELTA_VERIFIED) { |
| finishVerification(); |
| fState = VERIFICATION_COMPLETE; |
| } |
| return fIsDeltaValid; |
| } |
| |
| /** |
| * Tests message formatting. This main method does not represent the |
| * intended use of the ResourceDeltaVerifier. See the class comment |
| * for instructions on using the verifier. |
| */ |
| public static void main(String[] args) { |
| ResourceDeltaVerifier comparer = new ResourceDeltaVerifier(); |
| |
| int status = IResourceDelta.CHANGED; |
| int changeFlags = IResourceDelta.CONTENT; |
| int expectedStatus = IResourceDelta.CHANGED; |
| int actualStatus = IResourceDelta.REMOVED; |
| int expectedChangeFlags = IResourceDelta.OPEN; |
| int actualChangeFlags = 0; |
| int formerChildStatus = expectedStatus; |
| int latterChildStatus = actualStatus; |
| |
| IPath path = new Path("/a/b/c"); |
| IPath path2 = new Path("/a/b/d"); |
| IPath expectedFullPath = path; |
| IPath actualFullPath = path2; |
| IPath expectedMovedFromPath = path; |
| IPath actualMovedFromPath = path2; |
| IPath expectedMovedToPath = path; |
| IPath actualMovedToPath = path2; |
| IPath expectedProjectRelativePath = new Path("b/c"); |
| IPath actualProjectRelativePath = new Path("b/d"); |
| |
| comparer.fMessage.append("Checking delta for "); |
| comparer.fMessage.append(path); |
| comparer.fMessage.append("\n"); |
| |
| comparer.recordConflictingChange(expectedStatus, actualStatus, expectedChangeFlags, actualChangeFlags); |
| comparer.recordConflictingFullPaths(expectedFullPath, actualFullPath); |
| comparer.recordConflictingMovedFromPaths(expectedMovedFromPath, actualMovedFromPath); |
| comparer.recordConflictingMovedToPaths(expectedMovedToPath, actualMovedToPath); |
| comparer.recordConflictingProjectRelativePaths(expectedProjectRelativePath, actualProjectRelativePath); |
| comparer.recordDuplicateChild(path, formerChildStatus, latterChildStatus, expectedStatus); |
| comparer.recordIllegalChild(path, expectedStatus, actualStatus); |
| comparer.recordMissingActualChange(status, changeFlags); |
| comparer.recordMissingChild(path, status, true); |
| comparer.recordMissingChild(path, status, false); |
| comparer.recordMissingExpectedChange(status, changeFlags); |
| |
| System.out.print(comparer.fMessage.toString()); |
| } |
| |
| private void recordConflictingChange(int expectedKind, int kind, int expectedChangeFlags, int changeFlags) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tConflicting change\n"); |
| |
| if (expectedKind != kind) { |
| fMessage.append("\t\tExpected kind: <"); |
| fMessage.append(convertKind(expectedKind)); |
| fMessage.append("> actual kind: <"); |
| fMessage.append(convertKind(kind)); |
| fMessage.append(">\n"); |
| } |
| |
| if (expectedChangeFlags != changeFlags) { |
| fMessage.append("\t\tExpected change flags: <"); |
| fMessage.append(convertChangeFlags(expectedChangeFlags)); |
| fMessage.append("> actual change flags: <"); |
| fMessage.append(convertChangeFlags(changeFlags)); |
| fMessage.append(">\n"); |
| } |
| } |
| |
| private void recordConflictingFullPaths(IPath expectedFullPath, IPath actualFullPath) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tConflicting full paths\n"); |
| |
| fMessage.append("\t\tExpected full path: "); |
| fMessage.append(expectedFullPath); |
| fMessage.append("\n"); |
| |
| fMessage.append("\t\tActual full path: "); |
| fMessage.append(actualFullPath); |
| fMessage.append("\n"); |
| } |
| |
| private void recordConflictingMovedFromPaths(IPath expectedMovedFromPath, IPath actualMovedFromPath) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tConflicting moved from paths\n"); |
| |
| fMessage.append("\t\tExpected moved from path: "); |
| fMessage.append(expectedMovedFromPath); |
| fMessage.append("\n"); |
| |
| fMessage.append("\t\tActual moved from path: "); |
| fMessage.append(actualMovedFromPath); |
| fMessage.append("\n"); |
| } |
| |
| private void recordConflictingMovedToPaths(IPath expectedMovedToPath, IPath actualMovedToPath) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tConflicting moved to paths\n"); |
| |
| fMessage.append("\t\tExpected moved to path: "); |
| fMessage.append(expectedMovedToPath); |
| fMessage.append("\n"); |
| |
| fMessage.append("\t\tActual moved to path: "); |
| fMessage.append(actualMovedToPath); |
| fMessage.append("\n"); |
| } |
| |
| private void recordConflictingProjectRelativePaths(IPath expectedProjectRelativePath, IPath actualProjectRelativePath) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tConflicting project relative paths\n"); |
| |
| fMessage.append("\t\tExpected project relative path: "); |
| fMessage.append(expectedProjectRelativePath); |
| fMessage.append("\n"); |
| |
| fMessage.append("\t\tActual project relative path: "); |
| fMessage.append(actualProjectRelativePath); |
| fMessage.append("\n"); |
| } |
| |
| private void recordDuplicateChild(IPath path, int formerChildKind, int latterChildKind, int expectedKind) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tDuplicate child: "); |
| fMessage.append(path); |
| fMessage.append("\n"); |
| |
| fMessage.append("\t\tProduced by IResourceDelta.get"); |
| |
| switch (expectedKind) { |
| case IResourceDelta.ADDED : |
| fMessage.append("Added"); |
| break; |
| case IResourceDelta.CHANGED : |
| fMessage.append("Changed"); |
| break; |
| case IResourceDelta.REMOVED : |
| fMessage.append("Removed"); |
| break; |
| } |
| |
| fMessage.append("Children()\n"); |
| |
| fMessage.append("\t\tFormer child's status: "); |
| fMessage.append(convertKind(formerChildKind)); |
| fMessage.append("\n"); |
| |
| fMessage.append("\t\tLatter child's status: "); |
| fMessage.append(convertKind(latterChildKind)); |
| fMessage.append("\n"); |
| } |
| |
| private void recordIllegalChild(IPath path, int expectedKind, int actualKind) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tIllegal child: "); |
| fMessage.append(path); |
| fMessage.append("\n"); |
| |
| fMessage.append("\t\tProduced by IResourceDelta.get"); |
| |
| switch (expectedKind) { |
| case IResourceDelta.ADDED : |
| fMessage.append("Added"); |
| break; |
| case IResourceDelta.CHANGED : |
| fMessage.append("Changed"); |
| break; |
| case IResourceDelta.REMOVED : |
| fMessage.append("Removed"); |
| break; |
| } |
| |
| fMessage.append("Children()\n"); |
| |
| fMessage.append("\t\tIlleagal child's status: "); |
| fMessage.append(convertKind(actualKind)); |
| fMessage.append("\n"); |
| } |
| |
| private void recordMissingActualChange(int kind, int changeFlags) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tMissing actual change\n"); |
| fMessage.append("\t\tExpected kind: <"); |
| fMessage.append(convertKind(kind)); |
| fMessage.append(">\n"); |
| fMessage.append("\t\tExpected change flags: <"); |
| fMessage.append(convertChangeFlags(changeFlags)); |
| fMessage.append(">\n"); |
| } |
| |
| private void recordMissingChild(IPath path, int kind, boolean isMissingFromAffectedChildren) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tMissing child: "); |
| fMessage.append(path); |
| fMessage.append("\n"); |
| |
| fMessage.append("\t\tfrom IResourceDelta.getAffectedChildren("); |
| |
| if (!isMissingFromAffectedChildren) { |
| switch (kind) { |
| case IResourceDelta.ADDED : |
| fMessage.append("ADDED"); |
| break; |
| case IResourceDelta.CHANGED : |
| fMessage.append("CHANGED"); |
| break; |
| case IResourceDelta.REMOVED : |
| fMessage.append("REMOVED"); |
| break; |
| default : |
| fMessage.append(kind); |
| } |
| } |
| |
| fMessage.append(")\n"); |
| } |
| |
| private void recordMissingExpectedChange(int kind, int changeFlags) { |
| fIsDeltaValid = false; |
| |
| fMessage.append("\tMissing expected change\n"); |
| fMessage.append("\t\tActual kind: <"); |
| fMessage.append(convertKind(kind)); |
| fMessage.append(">\n"); |
| fMessage.append("\t\tActual change flags: <"); |
| fMessage.append(convertChangeFlags(changeFlags)); |
| fMessage.append(">\n"); |
| } |
| |
| /** |
| * Resets the listener to its initial state. |
| */ |
| public void reset() { |
| fExpectedChanges.clear(); |
| fIsDeltaValid = true; |
| fMessage.setLength(0); |
| fState = RECEIVING_INPUTS; |
| } |
| |
| private void resetIfNecessary() { |
| if (fState == DELTA_VERIFIED) { |
| reset(); |
| } |
| } |
| |
| /** |
| * Part of the <code>IResourceChangedListener</code> interface. |
| * @see IResourceChangedListener |
| */ |
| @Override |
| public void resourceChanged(IResourceChangeEvent e) { |
| verifyDelta(e.getDelta()); |
| } |
| |
| /** |
| * Compares the given delta with the expected changes. Recursively |
| * compares child deltas. |
| */ |
| public void verifyDelta(IResourceDelta delta) { |
| internalVerifyDelta(delta); |
| fState = DELTA_VERIFIED; |
| } |
| |
| /** |
| * Appends additional information to the current validation error message. |
| * |
| * @param message |
| * the additional information to append |
| */ |
| protected void appendToMessage(String message) { |
| fMessage.append(message); |
| fMessage.append(System.lineSeparator()); |
| } |
| } |