Skip to main content
summaryrefslogtreecommitdiffstats
blob: 7188adcb0c8c498f40262acacf12425125b1adfd (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
/**
 * Copyright (c) 2013, 2016 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 org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.BasicMonitor;
import org.eclipse.emf.common.util.Monitor;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.conflict.MatchBasedConflictDetector;
import org.eclipse.emf.compare.conflict.IConflictDetector;
import org.eclipse.emf.compare.diff.DefaultDiffEngine;
import org.eclipse.emf.compare.diff.DiffBuilder;
import org.eclipse.emf.compare.diff.IDiffEngine;
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.ConflictTest;
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 ConflictTest} on
 * the result of a conflict detection process.
 * 
 * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
 */
public class ConflictStatement 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 actual test method. */
	private final FrameworkMethod test;

	/**
	 * Instantiates our statement given its target object and tuple as well as the 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
	 *            and diff.
	 * @param test
	 *            The actual test method.
	 */
	public ConflictStatement(Object testObject, ResultStatement<NotifierTuple> tupleStatement,
			FrameworkMethod test) {
		this.testObject = testObject;
		this.tupleStatement = tupleStatement;
		this.test = test;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.junit.runners.model.Statement#evaluate()
	 */
	@Override
	public void evaluate() throws Throwable {
		tupleStatement.evaluate();
		final NotifierTuple tuple = tupleStatement.getResult();

		final ConflictTest annotation = test.getAnnotation(ConflictTest.class);
		final IComparisonScope scope = createComparisonScope(tuple, annotation);
		final IMatchEngine matchEngine = createMatchEngine(annotation);
		final IDiffEngine diffEngine = createDiffEngine(annotation);
		final IConflictDetector detector = new MatchBasedConflictDetector();
		final Monitor monitor = new BasicMonitor();

		final Comparison comparison = matchEngine.match(scope, new BasicMonitor());
		diffEngine.diff(comparison, new BasicMonitor());
		detector.detect(comparison, monitor);

		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(ConflictTest annotation) {
		final Class<? extends IMatchEngine> engineClass = annotation.matchEngine();

		IMatchEngine engine = null;
		try {
			engine = engineClass.newInstance();
		} catch (InstantiationException e) {
			// Swallow : we'll create a default engine instead.
		} catch (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 diff engine specified by the given annotation if it has a public no-arg constructor, use
	 * the {@link DefaultDiffEngine default} otherwise.
	 * 
	 * @param annotation
	 *            The annotation on which is defined the diff engine we are to use.
	 * @return An instance of the specified diff engine if it has a public no-arg constructor; an instance of
	 *         the {@link DefaultDiffEngine} otherwise.
	 */
	private static IDiffEngine createDiffEngine(ConflictTest annotation) {
		final Class<? extends IDiffEngine> engineClass = annotation.diffEngine();

		IDiffEngine engine = null;
		try {
			engine = engineClass.newInstance();
		} catch (InstantiationException e) {
			// Swallow : we'll create a default engine instead.
		} catch (IllegalAccessException e) {
			// Swallow : we'll create a default engine instead.
		}
		if (engine == null) {
			engine = new DefaultDiffEngine(new DiffBuilder());
		}
		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, ConflictTest 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;
	}
}

Back to the top