/**
* 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.fullcomparison;
import static org.eclipse.emf.compare.tests.framework.EMFCompareAssert.assertAdded;
import static org.eclipse.emf.compare.tests.framework.EMFCompareAssert.assertAddedToReference;
import static org.eclipse.emf.compare.tests.framework.EMFCompareAssert.assertAllMatched;
import static org.eclipse.emf.compare.tests.framework.EMFCompareAssert.assertChangedAttribute;
import static org.eclipse.emf.compare.tests.framework.EMFCompareAssert.assertChangedReference;
import static org.eclipse.emf.compare.tests.framework.EMFCompareAssert.assertRemoved;
import static org.eclipse.emf.compare.tests.framework.EMFCompareAssert.assertRemovedFromReference;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.List;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.Conflict;
import org.eclipse.emf.compare.ConflictKind;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.MatchResource;
import org.eclipse.emf.compare.scope.IComparisonScope;
import org.eclipse.emf.compare.tests.framework.EMFCompareTestBase;
import org.eclipse.emf.compare.tests.framework.IdentifierMatchValidator;
import org.eclipse.emf.compare.tests.framework.NotifierTuple;
import org.eclipse.emf.compare.tests.framework.junit.EMFCompareTestRunner;
import org.eclipse.emf.compare.tests.framework.junit.annotation.BeforeMatch;
import org.eclipse.emf.compare.tests.framework.junit.annotation.ConflictTest;
import org.eclipse.emf.compare.tests.framework.junit.annotation.DiffTest;
import org.eclipse.emf.compare.tests.framework.junit.annotation.MatchTest;
import org.eclipse.emf.compare.tests.framework.junit.annotation.UseCase;
import org.eclipse.emf.compare.tests.fullcomparison.data.identifier.IdentifierMatchInputData;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.junit.runner.RunWith;
@RunWith(EMFCompareTestRunner.class)
@SuppressWarnings("nls")
public class IdentifierComparisonTest extends EMFCompareTestBase {
private IdentifierMatchInputData inputData = new IdentifierMatchInputData();
@UseCase("Extended library three-way")
public NotifierTuple extlibrary3WayTuple() throws IOException {
final Resource left = inputData.getExtlibraryLeft();
final Resource right = inputData.getExtlibraryRight();
final Resource origin = inputData.getExtlibraryOrigin();
return new NotifierTuple(left, right, origin);
}
@UseCase("Extended library two-way")
public NotifierTuple extlibrary2WayTuple() throws IOException {
final Resource left = inputData.getExtlibraryLeft();
final Resource right = inputData.getExtlibraryRight();
return new NotifierTuple(left, right, null);
}
@BeforeMatch
public void beforeMatch(NotifierTuple tuple) {
assertNotNull(tuple);
assertTrue(tuple.getLeft() instanceof Resource);
assertTrue(tuple.getRight() instanceof Resource);
// We have both two-way and three-way use cases here
}
@MatchTest
public void testIdentifierMatch(IComparisonScope scope, Comparison comparison) {
final Resource left = (Resource)scope.getLeft();
final Resource right = (Resource)scope.getRight();
final Resource origin = (Resource)scope.getOrigin();
assertSame(Boolean.valueOf(origin != null), Boolean.valueOf(comparison.isThreeWay()));
assertEquals(1, comparison.getMatchedResources().size());
final MatchResource matchedResource = comparison.getMatchedResources().get(0);
assertEquals(left.getURI().toString(), matchedResource.getLeftURI());
assertEquals(right.getURI().toString(), matchedResource.getRightURI());
if (origin != null) {
assertEquals(origin.getURI().toString(), matchedResource.getOriginURI());
}
// Validate that all matches point to sides that have the same IDs, and that there is only 1 Match for
// one "ID" (if two EObjects on two different sides have the same ID, they share the same Match).
final IdentifierMatchValidator validator = new IdentifierMatchValidator();
validator.validate(comparison);
// Make sure that we have a Match for all EObjects of this scope
final List<EObject> leftChildren = getAllProperContent(left);
final List<EObject> rightChildren = getAllProperContent(right);
final List<EObject> originChildren = getAllProperContent(origin);
assertAllMatched(leftChildren, comparison, scope);
assertAllMatched(rightChildren, comparison, scope);
assertAllMatched(originChildren, comparison, scope);
}
@DiffTest
public void testIdentifierDiffTest(@SuppressWarnings("unused") IComparisonScope scope,
Comparison comparison) {
final List<Diff> differences = comparison.getDifferences();
// See file org.eclipse.emf.compare.tests.model.mock.CHANGES for the description of these
assertAdded(differences, "extlibrary.BookCategory.Encyclopedia", DifferenceSource.LEFT);
assertAdded(differences, "extlibrary.BookCategory.Dictionary", DifferenceSource.LEFT);
assertAdded(differences, "extlibrary.Magazine", DifferenceSource.LEFT);
assertAdded(differences, "extlibrary.Magazine.title", DifferenceSource.LEFT);
assertAdded(differences, "extlibrary.Magazine.pages", DifferenceSource.LEFT);
assertAdded(differences, "extlibrary.Person.fullName", DifferenceSource.LEFT);
assertRemoved(differences, "extlibrary.Periodical", DifferenceSource.LEFT);
assertRemoved(differences, "extlibrary.Periodical.issuesPerYear", DifferenceSource.LEFT);
assertRemoved(differences, "extlibrary.Person.firstName", DifferenceSource.LEFT);
assertChangedAttribute(differences, "extlibrary.Lendable", "name", "Lendable", "Borrowable",
DifferenceSource.LEFT);
assertAddedToReference(differences, "extlibrary.Magazine", "eSuperTypes",
"extlibrary.CirculatingItem", DifferenceSource.LEFT);
assertRemovedFromReference(differences, "extlibrary.Periodical", "eSuperTypes", "extlibrary.Item",
DifferenceSource.LEFT);
assertChangedReference(differences, "extlibrary.Magazine.title", "eType", null, "ecore.EString",
DifferenceSource.LEFT);
assertChangedReference(differences, "extlibrary.Magazine.pages", "eType", null, "ecore.EInt",
DifferenceSource.LEFT);
assertChangedReference(differences, "extlibrary.Person.fullName", "eType", null, "ecore.EString",
DifferenceSource.LEFT);
assertChangedReference(differences, "extlibrary.Periodical.issuesPerYear", "eType", "ecore.EInt",
null, DifferenceSource.LEFT);
assertChangedReference(differences, "extlibrary.Person.firstName", "eType", "ecore.EString", null,
DifferenceSource.LEFT);
// some diffs change according to the presence of an origin.
if (comparison.isThreeWay()) {
// This one will be detected differently in two-way
assertRemoved(differences, "extlibrary.Person.lastName", DifferenceSource.LEFT);
assertChangedReference(differences, "extlibrary.Person.lastName", "eType", "ecore.EString", null,
DifferenceSource.LEFT);
final DifferenceSource side = DifferenceSource.RIGHT;
assertAdded(differences, "extlibrary.BookCategory.Manga", side);
assertAdded(differences, "extlibrary.BookCategory.Manhwa", side);
assertAdded(differences, "extlibrary.Book.subtitle", side);
assertAdded(differences, "extlibrary.Magazine", side);
assertAdded(differences, "extlibrary.TitledItem", side);
assertAdded(differences, "extlibrary.TitledItem.title", side);
assertRemoved(differences, "extlibrary.Book.title", side);
assertRemoved(differences, "extlibrary.AudioVisualItem.title", side);
assertAddedToReference(differences, "extlibrary.Book", "eSuperTypes", "extlibrary.TitledItem",
side);
assertAddedToReference(differences, "extlibrary.Periodical", "eSuperTypes",
"extlibrary.TitledItem", side);
assertAddedToReference(differences, "extlibrary.AudioVisualItem", "eSuperTypes",
"extlibrary.TitledItem", side);
assertAddedToReference(differences, "extlibrary.Magazine", "eSuperTypes", "extlibrary.Periodical",
side);
assertChangedReference(differences, "extlibrary.Book.subtitle", "eType", null, "ecore.EString",
side);
assertChangedReference(differences, "extlibrary.TitledItem.title", "eType", null, "ecore.EString",
side);
assertChangedReference(differences, "extlibrary.Book.title", "eType", "ecore.EString", null,
side);
assertChangedReference(differences, "extlibrary.AudioVisualItem.title", "eType", "ecore.EString",
null, side);
/*
* The following are actually conflicts, most changes according to whether we are in three-way or
* not.
*/
assertChangedAttribute(differences, "extlibrary.AudioVisualItem.length", "name", "minutesLength",
"length", DifferenceSource.LEFT);
// These are actually pseudo-conflicts : same diff on both sides
assertRemoved(differences, "extlibrary.BookOnTape.reader", DifferenceSource.LEFT);
assertRemoved(differences, "extlibrary.BookOnTape.reader", DifferenceSource.RIGHT);
assertRemoved(differences, "extlibrary.Periodical.title", DifferenceSource.LEFT);
assertRemoved(differences, "extlibrary.Periodical.title", DifferenceSource.RIGHT);
assertChangedReference(differences, "extlibrary.BookOnTape.reader", "eType", "extlibrary.Person",
null, DifferenceSource.LEFT);
assertChangedReference(differences, "extlibrary.BookOnTape.reader", "eType", "extlibrary.Person",
null, DifferenceSource.RIGHT);
assertChangedReference(differences, "extlibrary.Periodical.title", "eType", "ecore.EString", null,
DifferenceSource.LEFT);
assertChangedReference(differences, "extlibrary.Periodical.title", "eType", "ecore.EString", null,
DifferenceSource.RIGHT);
/*
* These changes can only be detected with an origin : lastName has been removed in the left model
* and thus only the removal can be detected in two-way. Likewise, "minutesLength" has been
* renamed in both left and right, and thus no mention of that value can be found in two-way
*/
assertChangedAttribute(differences, "extlibrary.Person.familyName", "name", "lastName",
"familyName", side);
assertChangedAttribute(differences, "extlibrary.AudioVisualItem.length", "name", "minutesLength",
"minutes", side);
} else {
assertRemoved(differences, "extlibrary.Person.familyName", DifferenceSource.LEFT);
assertChangedReference(differences, "extlibrary.Person.familyName", "eType", "ecore.EString",
null, DifferenceSource.LEFT);
final DifferenceSource side = DifferenceSource.LEFT;
assertRemoved(differences, "extlibrary.BookCategory.Manga", side);
assertRemoved(differences, "extlibrary.BookCategory.Manhwa", side);
assertRemoved(differences, "extlibrary.Book.subtitle", side);
assertRemoved(differences, "extlibrary.Magazine", side);
assertRemoved(differences, "extlibrary.TitledItem", side);
assertRemoved(differences, "extlibrary.TitledItem.title", side);
assertAdded(differences, "extlibrary.Book.title", side);
assertAdded(differences, "extlibrary.AudioVisualItem.title", side);
assertRemovedFromReference(differences, "extlibrary.Book", "eSuperTypes", "extlibrary.TitledItem",
side);
assertRemovedFromReference(differences, "extlibrary.Periodical", "eSuperTypes",
"extlibrary.TitledItem", side);
assertRemovedFromReference(differences, "extlibrary.AudioVisualItem", "eSuperTypes",
"extlibrary.TitledItem", side);
assertRemovedFromReference(differences, "extlibrary.Magazine", "eSuperTypes",
"extlibrary.Periodical", side);
assertChangedReference(differences, "extlibrary.Book.subtitle", "eType", "ecore.EString", null,
side);
assertChangedReference(differences, "extlibrary.TitledItem.title", "eType", "ecore.EString", null,
side);
assertChangedReference(differences, "extlibrary.Book.title", "eType", null, "ecore.EString",
side);
assertChangedReference(differences, "extlibrary.AudioVisualItem.title", "eType", null,
"ecore.EString", side);
// This is a conflict, the expected diff is not the same in two-way
assertChangedAttribute(differences, "extlibrary.AudioVisualItem.length", "name", "minutes",
"length", DifferenceSource.LEFT);
}
// We should have no more differences than those
assertTrue(differences.isEmpty());
}
@ConflictTest
public void testIdentifierConflictTest(@SuppressWarnings("unused") IComparisonScope scope,
Comparison comparison) {
final List<Conflict> conflicts = comparison.getConflicts();
if (!comparison.isThreeWay()) {
assertTrue(conflicts.isEmpty());
return;
}
assertEquals(7, conflicts.size());
Conflict periodicalConflict = null;
Conflict titleConflict = null;
Conflict titleETypeConflict = null;
Conflict lastNameConflict = null;
Conflict minutesLengthConflict = null;
Conflict readerConflict = null;
Conflict readerETypeConflict = null;
for (Conflict conflict : conflicts) {
for (Diff diff : conflict.getDifferences()) {
boolean breakLoop = false;
final Match match = diff.getMatch();
if (isMatchOf(match, "Periodical") && conflict.getDifferences().size() == 3) {
periodicalConflict = conflict;
breakLoop = true;
} else if (isMatchOf(match, "Periodical")) {
titleConflict = conflict;
breakLoop = true;
} else if (isMatchOf(match, "Person")) {
lastNameConflict = conflict;
breakLoop = true;
} else if (isMatchOf(match, "BookOnTape")) {
readerConflict = conflict;
breakLoop = true;
} else if (isMatchOf(match, "minutesLength")) {
minutesLengthConflict = conflict;
breakLoop = true;
} else if (isMatchOf(match, "reader")) {
readerETypeConflict = conflict;
breakLoop = true;
} else if (isMatchOf(match, "title")) {
titleETypeConflict = conflict;
breakLoop = true;
}
if (breakLoop) {
break;
}
}
}
assertNotNull(periodicalConflict);
assertNotNull(titleConflict);
assertNotNull(titleETypeConflict);
assertNotNull(lastNameConflict);
assertNotNull(minutesLengthConflict);
assertNotNull(readerConflict);
assertNotNull(readerETypeConflict);
// These classic asserts will make the compiler happy.
assert periodicalConflict != null;
assert titleConflict != null;
assert titleETypeConflict != null;
assert lastNameConflict != null;
assert minutesLengthConflict != null;
assert readerConflict != null;
assert readerETypeConflict != null;
final List<Diff> periodicalDiffs = Lists.newArrayList(periodicalConflict.getDifferences());
assertSame(ConflictKind.REAL, periodicalConflict.getKind());
assertRemoved(periodicalDiffs, "extlibrary.Periodical", DifferenceSource.LEFT);
assertAddedToReference(periodicalDiffs, "extlibrary.Periodical", "eSuperTypes",
"extlibrary.TitledItem", DifferenceSource.RIGHT);
assertAddedToReference(periodicalDiffs, "extlibrary.Magazine", "eSuperTypes", "extlibrary.Periodical",
DifferenceSource.RIGHT);
assertTrue(periodicalDiffs.isEmpty());
final List<Diff> nameDiffs = Lists.newArrayList(lastNameConflict.getDifferences());
assertSame(ConflictKind.REAL, lastNameConflict.getKind());
assertRemoved(nameDiffs, "extlibrary.Person.lastName", DifferenceSource.LEFT);
assertChangedAttribute(nameDiffs, "extlibrary.Person.familyName", "name", "lastName", "familyName",
DifferenceSource.RIGHT);
assertTrue(nameDiffs.isEmpty());
final List<Diff> lengthDiffs = Lists.newArrayList(minutesLengthConflict.getDifferences());
assertSame(ConflictKind.REAL, minutesLengthConflict.getKind());
assertChangedAttribute(lengthDiffs, "extlibrary.AudioVisualItem.length", "name", "minutesLength",
"length", DifferenceSource.LEFT);
assertChangedAttribute(lengthDiffs, "extlibrary.AudioVisualItem.length", "name", "minutesLength",
"minutes", DifferenceSource.RIGHT);
assertTrue(lengthDiffs.isEmpty());
final List<Diff> titleDiffs = Lists.newArrayList(titleConflict.getDifferences());
assertSame(ConflictKind.PSEUDO, titleConflict.getKind());
assertRemoved(titleDiffs, "extlibrary.Periodical.title", DifferenceSource.LEFT);
assertRemoved(titleDiffs, "extlibrary.Periodical.title", DifferenceSource.RIGHT);
assertTrue(titleDiffs.isEmpty());
final List<Diff> titleETypeDiffs = Lists.newArrayList(titleETypeConflict.getDifferences());
assertSame(ConflictKind.PSEUDO, titleConflict.getKind());
assertChangedReference(titleETypeDiffs, "extlibrary.Periodical.title", "eType", "ecore.EString", null,
DifferenceSource.LEFT);
assertChangedReference(titleETypeDiffs, "extlibrary.Periodical.title", "eType", "ecore.EString", null,
DifferenceSource.RIGHT);
assertTrue(titleETypeDiffs.isEmpty());
final List<Diff> readerDiffs = Lists.newArrayList(readerConflict.getDifferences());
assertSame(ConflictKind.PSEUDO, readerConflict.getKind());
assertRemoved(readerDiffs, "extlibrary.BookOnTape.reader", DifferenceSource.LEFT);
assertRemoved(readerDiffs, "extlibrary.BookOnTape.reader", DifferenceSource.RIGHT);
assertTrue(readerDiffs.isEmpty());
final List<Diff> readerETypeDiffs = Lists.newArrayList(readerETypeConflict.getDifferences());
assertSame(ConflictKind.PSEUDO, readerETypeConflict.getKind());
assertChangedReference(readerETypeDiffs, "extlibrary.BookOnTape.reader", "eType", "extlibrary.Person",
null, DifferenceSource.LEFT);
assertChangedReference(readerETypeDiffs, "extlibrary.BookOnTape.reader", "eType", "extlibrary.Person",
null, DifferenceSource.RIGHT);
assertTrue(readerETypeDiffs.isEmpty());
}
private boolean isMatchOf(Match match, String name) {
boolean isMatch = false;
if (match.getLeft() instanceof ENamedElement) {
if (((ENamedElement)match.getLeft()).getName().equals(name)) {
isMatch = true;
}
}
if (!isMatch && match.getRight() instanceof ENamedElement) {
if (((ENamedElement)match.getRight()).getName().equals(name)) {
isMatch = true;
}
}
if (!isMatch && match.getOrigin() instanceof ENamedElement) {
if (((ENamedElement)match.getOrigin()).getName().equals(name)) {
isMatch = true;
}
}
return isMatch;
}
}