blob: 266e2f33b221bbb366b9076e6ddb4cb4da314bd5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* 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() {
StringBuffer buf = new StringBuffer("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 StringBuffer fMessage = new StringBuffer();
/**
* 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";
}
StringBuffer buf = new StringBuffer();
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;
}
}