Skip to main content
summaryrefslogtreecommitdiffstats
blob: d9cc0962cbf7768f227364ea3a319a3d75166b99 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*******************************************************************************
 * Copyright (c) 2012 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 junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
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 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;
	}
}

Back to the top