org.eclipse.emf.compare.tests.framework.EMFCompareAssert.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.emf.compare.tests.framework.EMFCompareAssert.java

Source

/*******************************************************************************
 * Copyright (c) 2012, 2014 Obeo.
 * 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:
 *     Obeo - initial API and implementation
 *******************************************************************************/
package org.eclipse.emf.compare.tests.framework;

import static com.google.common.base.Predicates.and;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.added;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.addedToReference;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.changedAttribute;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.changedReference;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.removed;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.removedFromReference;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.scope.FilterComparisonScope;
import org.eclipse.emf.compare.scope.IComparisonScope;
import org.eclipse.emf.compare.utils.EMFComparePredicates;
import org.eclipse.emf.ecore.EObject;

/**
 * Provides specific assertions for EMF Compare tests.
 * 
 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
 */
@SuppressWarnings("nls")
public class EMFCompareAssert {
    /**
     * This can be used to check whether all objects of the given list have a corresponding {@link Match} in
     * the given {@link Comparison}. If one of said EObjects is not matched, we will check whether it is
     * included in the given <code>scope</code> if it is a {@link FilterComparisonScope}.
     * 
     * @param eObjects
     *            The list of EObjects for which we need corresponding {@link Match}es.
     * @param comparison
     *            The {@link Comparison} in which we are to check for Matches.
     * @param scope
     *            The scope that has been used to create the given <code>comparison</code>.
     */
    public static void assertAllMatched(List<EObject> eObjects, Comparison comparison, IComparisonScope scope) {
        final Predicate<? super EObject> scopeFilter;
        if (scope instanceof FilterComparisonScope) {
            scopeFilter = getResourceChildrenFilteringPredicate((FilterComparisonScope) scope);
        } else {
            scopeFilter = Predicates.alwaysTrue();
        }

        final Iterator<EObject> eObjectIterator = eObjects.iterator();
        while (eObjectIterator.hasNext()) {
            final EObject eObject = eObjectIterator.next();
            final Match match = comparison.getMatch(eObject);
            assertTrue(eObject + " has no match", match != null || !scopeFilter.apply(eObject));
        }
    }

    /**
     * Asserts that the given list of differences contains a ReferenceChange describing the given change for a
     * single-valued reference. The {@code differences} list will be updated by this call, removing the
     * corresponding Diff if it could be located.
     * <p>
     * Note that in order for this to work, we expect the EObjects to have a "name" feature returning a String
     * so that we can compare it to the given qualified names.
     * </p>
     * 
     * @param differences
     *            List of differences in which to seek for a particular reference change.
     * @param qualifiedName
     *            Qualified name of the EObject which reference we expect to have changed.
     * @param referenceName
     *            Name of the reference which values we expect to have changed. <b>Note</b> that we expect
     *            this reference to be single-valued.
     * @param fromQualifiedName
     *            Qualified name of the original value of this reference (can be either the origin or right
     *            value).
     * @param toQualifiedName
     *            Qualified name of the value to which this reference has been changed (can be either left or
     *            right in three-way comparisons, only left for two-way).
     * @param side
     *            The side from which we expect this diff to originate.
     * @see EMFComparePredicates#changedReference(String, String, String, String)
     */
    public static void assertChangedReference(List<Diff> differences, String qualifiedName, String referenceName,
            String fromQualifiedName, String toQualifiedName, DifferenceSource side) {
        final Predicate<? super Diff> changedReferenceOnSide = and(fromSide(side),
                changedReference(qualifiedName, referenceName, fromQualifiedName, toQualifiedName));
        final Diff matchingDiff = removeFirst(differences.iterator(), changedReferenceOnSide);
        assertNotNull(matchingDiff);
    }

    /**
     * Asserts that the given list of differences contains a ReferenceChange describing the removal of a value
     * from a multi-valued reference. The {@code differences} list will be updated by this call, removing the
     * corresponding Diff if it could be located.
     * <p>
     * Note that in order for this to work, we expect the EObjects to have a "name" feature returning a String
     * so that we can compare it to the given qualified names.
     * </p>
     * 
     * @param differences
     *            List of differences in which to seek for a particular reference change.
     * @param qualifiedName
     *            Qualified name of the EObject which reference we expect to have changed.
     * @param referenceName
     *            Name of the reference which values we expect to have changed. <b>Note</b> that we expect
     *            this reference to be multi-valued.
     * @param removedValueQualifiedName
     *            Qualified name of the value we expect to have been removed from that reference's list of
     *            values.
     * @param side
     *            The side from which we expect this diff to originate.
     * @see EMFComparePredicates#removedFromReference(String, String, String)
     */
    public static void assertRemovedFromReference(List<Diff> differences, String qualifiedName,
            String referenceName, String removedValueQualifiedName, DifferenceSource side) {
        final Predicate<? super Diff> removedFromReferenceOnSide = and(fromSide(side),
                removedFromReference(qualifiedName, referenceName, removedValueQualifiedName));
        final Diff matchingDiff = removeFirst(differences.iterator(), removedFromReferenceOnSide);
        assertNotNull(matchingDiff);
    }

    /**
     * Asserts that the given list of differences contains a ReferenceChange describing the addition of a
     * value into a multi-valued reference. The {@code differences} list will be updated by this call,
     * removing the corresponding Diff if it could be located.
     * <p>
     * Note that in order for this to work, we expect the EObjects to have a "name" feature returning a String
     * so that we can compare it to the given qualified names.
     * </p>
     * 
     * @param differences
     *            List of differences in which to seek for a particular reference change.
     * @param qualifiedName
     *            Qualified name of the EObject which reference we expect to have changed.
     * @param referenceName
     *            Name of the reference which values we expect to have changed. <b>Note</b> that we expect
     *            this reference to be multi-valued.
     * @param addedValueQualifiedName
     *            Qualified name of the value we expect to have been added to that reference's list of values.
     * @param side
     *            The side from which we expect this diff to originate.
     * @see EMFComparePredicates#addedToReference(String, String, String)
     */
    public static void assertAddedToReference(List<Diff> differences, String qualifiedName, String referenceName,
            String addedValueQualifiedName, DifferenceSource side) {
        final Predicate<? super Diff> addedToReferenceOnSide = and(fromSide(side),
                addedToReference(qualifiedName, referenceName, addedValueQualifiedName));
        final Diff matchingDiff = removeFirst(differences.iterator(), addedToReferenceOnSide);
        assertNotNull(matchingDiff);
    }

    /**
     * Asserts that the given list of differences contains an AttributeChange describing the given change for
     * a single-valued attribute. The {@code differences} list will be updated by this call, removing the
     * corresponding Diff if it could be located.
     * <p>
     * Note that in order for this to work, we expect the EObjects to have a "name" feature returning a String
     * so that we can compare it to the given qualified names.
     * </p>
     * 
     * @param differences
     *            List of differences in which to seek for a particular attribute change.
     * @param qualifiedName
     *            Qualified name of the EObject which attribute we expect to have changed.
     * @param attributeName
     *            Name of the attribute which values we expect to have changed. <b>Note</b> that we expect
     *            this attribute to be single-valued.
     * @param fromValue
     *            The original value of this attribute. Can be either the origin or right value.
     * @param toValue
     *            The value to which this attribute has been changed. Can be either left or right for a
     *            three-way comparison, only left in two-way.
     * @param side
     *            The side from which we expect this diff to originate.
     * @see EMFComparePredicates#changedAttribute(String, String, Object, Object)
     */
    public static void assertChangedAttribute(List<Diff> differences, String qualifiedName, String attributeName,
            Object fromValue, Object toValue, DifferenceSource side) {
        final Predicate<? super Diff> changedAttributeOnSide = and(fromSide(side),
                changedAttribute(qualifiedName, attributeName, fromValue, toValue));
        final Diff matchingDiff = removeFirst(differences.iterator(), changedAttributeOnSide);
        assertNotNull(matchingDiff);
    }

    /**
     * Asserts that the given list of differences contains a ReferenceChange describing the given element
     * addition. This is only meant for containment changes. The {@code differences} list will be updated by
     * this call, removing the corresponding Diff if it could be located.
     * <p>
     * Note that in order for this to work, we expect the EObjects to have a "name" feature returning a String
     * so that we can compare it to the given qualified names.
     * </p>
     * 
     * @param differences
     *            List of differences in which to seek for a particular element addition.
     * @param qualifiedName
     *            Qualified name of the EObject we expect to have been added.
     * @param side
     *            The side from which we expect this diff to originate.
     * @see EMFComparePredicates#added(String)
     */
    public static void assertAdded(List<Diff> differences, String qualifiedName, DifferenceSource side) {
        final Predicate<? super Diff> addedOnSide = and(fromSide(side), added(qualifiedName));
        final Diff matchingDiff = removeFirst(differences.iterator(), addedOnSide);
        assertNotNull(matchingDiff);
    }

    /**
     * Asserts that the given list of differences contains a ReferenceChange describing the given element
     * deletion. This is only meant for containment changes. The {@code differences} list will be updated by
     * this call, removing the corresponding Diff if it could be located.
     * <p>
     * Note that in order for this to work, we expect the EObjects to have a "name" feature returning a String
     * so that we can compare it to the given qualified names.
     * </p>
     * 
     * @param differences
     *            List of differences in which to seek for a particular element deletion.
     * @param qualifiedName
     *            Qualified name of the EObject we expect to have been deleted.
     * @param side
     *            The side from which we expect this diff to originate.
     * @see EMFComparePredicates#removed(String)
     */
    public static void assertRemoved(List<Diff> differences, String qualifiedName, DifferenceSource side) {
        final Predicate<? super Diff> removedOnSide = and(fromSide(side), removed(qualifiedName));
        final Diff matchingDiff = removeFirst(differences.iterator(), removedOnSide);
        assertNotNull(matchingDiff);
    }

    /**
     * Retrieves the Predicate that is used by the given scope in order to filter out Resource children.
     * <p>
     * This uses reflection to access a protected field, and is only meant for testing purposes.
     * </p>
     * 
     * @param scope
     *            The scope which predicate we need to retrieve.
     * @return The predicate that was used by the given scope to filter out Resource children.
     */
    @SuppressWarnings("unchecked")
    private static Predicate<? super EObject> getResourceChildrenFilteringPredicate(FilterComparisonScope scope) {
        final String fieldName = "resourceContentFilter"; //$NON-NLS-1$
        try {
            final Field field = FilterComparisonScope.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            return (Predicate<? super EObject>) field.get(scope);
        } catch (Exception e) {
            fail("Could not retrieve the filtering predicate of " + scope.getClass().getName()); //$NON-NLS-1$
        }
        // Unreachable code
        return null;
    }

    /**
     * Removes and returns the first element returned by {@code iterator} that satisfies the given predicate.
     * 
     * @param iterator
     *            Iterators over which elements we are to iterate.
     * @param predicate
     *            The predicate which needs to be satisified.
     * @return The first element of {@code iterator} that satisfies {@code predicate}, {@code null} if none.
     */
    private static <T> T removeFirst(Iterator<T> iterator, Predicate<? super T> predicate) {
        while (iterator.hasNext()) {
            T element = iterator.next();
            if (predicate.apply(element)) {
                iterator.remove();
                return element;
            }
        }
        return null;
    }
}