blob: 626a0effb29eca5fb44be84ee6d2a7383003d3a8 [file] [log] [blame]
/**
* 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.junit.internal;
import java.lang.reflect.Constructor;
import java.util.List;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.BasicMonitor;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.match.DefaultComparisonFactory;
import org.eclipse.emf.compare.match.DefaultEqualityHelperFactory;
import org.eclipse.emf.compare.match.DefaultMatchEngine;
import org.eclipse.emf.compare.match.IMatchEngine;
import org.eclipse.emf.compare.match.eobject.EcoreWeightProvider;
import org.eclipse.emf.compare.match.eobject.EditionDistance;
import org.eclipse.emf.compare.match.eobject.IEObjectMatcher;
import org.eclipse.emf.compare.match.eobject.IdentifierEObjectMatcher;
import org.eclipse.emf.compare.match.eobject.ProximityEObjectMatcher;
import org.eclipse.emf.compare.scope.DefaultComparisonScope;
import org.eclipse.emf.compare.scope.IComparisonScope;
import org.eclipse.emf.compare.tests.framework.NotifierTuple;
import org.eclipse.emf.compare.tests.framework.junit.annotation.MatchTest;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
/**
* This implementation of a {@link Statement} allows us to call methods annotated with {@link MatchTest} on
* the result of a Matching process.
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
public class MatchStatement extends Statement {
/** Target of the test. */
private final Object testObject;
/**
* The statement that should be executed to retrieve the {@link NotifierTuple} we are to match.
*/
private final ResultStatement<NotifierTuple> tupleStatement;
/** The methods to call before the match, if any. */
private final List<FrameworkMethod> beforeTest;
/** The actual test method. */
private final FrameworkMethod test;
/**
* Instantiates our statement given its target object and tuple as well as the befores and test methods.
*
* @param testObject
* Target of the test.
* @param tupleStatement
* The statement that should be executed to retrieve the {@link NotifierTuple} we are to match.
* @param beforeTest
* If there were any method to call before launching the match, this will contain them.
* @param test
* The actual test method.
*/
public MatchStatement(Object testObject, ResultStatement<NotifierTuple> tupleStatement,
List<FrameworkMethod> beforeTest, FrameworkMethod test) {
this.testObject = testObject;
this.tupleStatement = tupleStatement;
this.beforeTest = beforeTest;
this.test = test;
}
/**
* {@inheritDoc}
*
* @see org.junit.runners.model.Statement#evaluate()
*/
@Override
public void evaluate() throws Throwable {
tupleStatement.evaluate();
final NotifierTuple tuple = tupleStatement.getResult();
for (FrameworkMethod before : beforeTest) {
before.invokeExplosively(testObject, tuple);
}
final MatchTest annotation = test.getAnnotation(MatchTest.class);
final IMatchEngine engine = createMatchEngine(annotation);
final IComparisonScope scope = createComparisonScope(tuple, annotation);
final Comparison comparison = engine.match(scope, new BasicMonitor());
test.invokeExplosively(testObject, scope, comparison);
}
/**
* Creates the match engine specified by the given annotation if it has a public no-arg constructor, use
* the {@link DefaultMatchEngine default} otherwise.
*
* @param annotation
* The annotation on which is defined the match engine we are to use.
* @return An instance of the specified match engine if it has a public no-arg constructor; an instance of
* the {@link DefaultMatchEngine} otherwise.
*/
private static IMatchEngine createMatchEngine(MatchTest annotation) {
final Class<? extends IMatchEngine> engineClass = annotation.matchEngine();
IMatchEngine engine = null;
try {
engine = engineClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
// Swallow : we'll create a default engine instead.
}
if (engine == null) {
final IEObjectMatcher contentMatcher = new ProximityEObjectMatcher(
EditionDistance.builder().weightProvider(new EcoreWeightProvider()).build());
final IEObjectMatcher matcher = new IdentifierEObjectMatcher(contentMatcher);
engine = new DefaultMatchEngine(matcher,
new DefaultComparisonFactory(new DefaultEqualityHelperFactory()));
}
return engine;
}
/**
* Creates the comparison scope specified by the given annotation if it has a public constructor taking
* three {@link Notifier}s as parameters. We'll return an instance of the {@link DefaultComparisonScope}
* otherwise.
*
* @param tuple
* The tuple for which we need a comparison scope.
* @param annotation
* The annotation on which is specified the desired scope's class.
* @return An instance of the specified comparison scope it it has the expected constructor, an instance
* of the {@link DefaultComparisonScope} otherwise.
*/
private static IComparisonScope createComparisonScope(NotifierTuple tuple, MatchTest annotation) {
final Class<? extends IComparisonScope> scopeClass = annotation.scope();
IComparisonScope scope = null;
try {
final Constructor<? extends IComparisonScope> constructor = scopeClass
.getConstructor(Notifier.class, Notifier.class, Notifier.class);
scope = constructor.newInstance(tuple.getLeft(), tuple.getRight(), tuple.getOrigin());
// CHECKSTYLE:OFF invoking a constructor requires 7 catches. Since
// we're swallowing all exceptions, we simply catch everything.
} catch (Exception e) {
// CHECKSTYLE:ON
// Swallow : we'll create a default engine instead.
}
if (scope == null) {
scope = new DefaultComparisonScope(tuple.getLeft(), tuple.getRight(), tuple.getOrigin());
}
return scope;
}
}