Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Delaigue2016-10-24 11:40:47 -0400
committerLaurent Delaigue2016-10-24 11:40:47 -0400
commit72972f4bb54dd7650da6f73aab42da39cda316f3 (patch)
treefa804dc8588ec647dc5de44a0f8db12d60079717
parent14123b883ed31ca999c92a153cd9ba4a01672212 (diff)
parente23418ba774fcdfbf97e13edc7e9bf4119b17231 (diff)
downloadorg.eclipse.emf.compare-72972f4bb54dd7650da6f73aab42da39cda316f3.tar.gz
org.eclipse.emf.compare-72972f4bb54dd7650da6f73aab42da39cda316f3.tar.xz
org.eclipse.emf.compare-72972f4bb54dd7650da6f73aab42da39cda316f3.zip
Merge branch 'master' into 3.3
Change-Id: I9ed00ead81d6c4685835b93c8eb2623751bfe7fb Signed-off-by: Laurent Delaigue <laurent.delaigue@obeo.fr>
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/egit/AbstractGitMergeTestCase.java31
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java32
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/resourceattachmentchange/move/ResourceAttachmentChangeMoveConflictTests.java82
-rw-r--r--plugins/org.eclipse.emf.compare.diagram.papyrus.tests/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/NodeMergeTest.java39
-rw-r--r--plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/MatchItemProviderSpec.java34
-rw-r--r--plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/OverlayImageProvider.java39
-rw-r--r--plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/ReferenceChangeItemProviderSpec.java15
-rw-r--r--plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AbstractTooltipProvider.java18
-rw-r--r--plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AttributeChangeTooltipProvider.java5
-rw-r--r--plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/FeatureMapChangeTooltipProvider.java5
-rw-r--r--plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ReferenceChangeTooltipProvider.java3
-rw-r--r--plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceAttachmentChangeTooltipProvider.java5
-rw-r--r--plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceLocationChangeTooltipProvider.java5
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui.tests.git.framework/src/org/eclipse/emf/compare/ide/ui/tests/git/framework/internal/statements/InternalGitTestSupport.java50
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java16
-rw-r--r--plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java3
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/META-INF/MANIFEST.MF4
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/MatchAccessorTest.java246
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/MatchAccessorInputData.java32
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/left.ecore15
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/origin.ecore15
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/right.ecore15
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/CascadingDiffFilterTest.java206
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/TechnicalitiesFilterTests.java86
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/ancestor.ecore3
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/left.ecore7
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/right.ecore3
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/ancestor.ecore7
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/left.ecore3
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/right.ecore5
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupTest.java625
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupWithRefinedDiffTestScenario.java109
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/AbstractTestTreeNodeItemProviderAdapter.java8
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/MatchOfContainmentReferenceChangeAdapterTest.java74
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/MatchOfContainmentReferenceChangeAdapterTestData.java33
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/left.ecore9
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/right.ecore6
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/suite/AllTests.java17
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui/META-INF/MANIFEST.MF1
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/factory/impl/MatchAccessorFactory.java39
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/impl/MatchAccessor.java27
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/CascadingDifferencesFilter.java53
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java29
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java260
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/match/MatchOfContainmentReferenceChangeProcessor.java78
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java11
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/EMFComparePredicatesTest.java182
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/GraphTest.java169
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/META-INF/MANIFEST.MF3
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/ConflictsGroupTest.java212
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/UMLJoiningConflictsWithOverlappingDiffsInputData.java32
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/left.uml13
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/origin.uml13
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/right.uml5
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/UMLConflictWithRefiningDiffInputData.java32
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/left.uml9
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/origin.uml6
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/right.uml4
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/suite/AllTests.java14
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/OpaqueElementBodyChangeAccessor.java7
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java11
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/multiplicitychanges/MultiplicityElementChangesTest.java186
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/stereotypes/AbstractStereotypedElementChangeTests.java47
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java180
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java125
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java112
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java1
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java1
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java1
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java1
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/postprocessor/factories/AbstractChangeFactory.java16
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java77
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/Graph.java7
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/MatchOfContainmentReferenceChangeAdapter.java61
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java161
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java154
76 files changed, 3526 insertions, 724 deletions
diff --git a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/egit/AbstractGitMergeTestCase.java b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/egit/AbstractGitMergeTestCase.java
index 676b61114..ba9e7e26a 100644
--- a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/egit/AbstractGitMergeTestCase.java
+++ b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/egit/AbstractGitMergeTestCase.java
@@ -201,18 +201,24 @@ public abstract class AbstractGitMergeTestCase {
private static void copyDirectoryContents(File rootDirectory, final File workingDirectory)
throws IOException {
- for (String child : rootDirectory.list()) {
- copyDirectory(new File(rootDirectory, child), new File(workingDirectory, child));
+ String[] list = rootDirectory.list();
+ if (list != null) {
+ for (String child : list) {
+ copyDirectory(new File(rootDirectory, child), new File(workingDirectory, child));
+ }
}
}
private static void copyDirectory(File source, File destination) throws IOException {
- if (source.isDirectory()) {
- if (!destination.exists()) {
+ if (source != null && source.isDirectory()) {
+ if (destination != null && !destination.exists()) {
destination.mkdir();
}
- for (String child : source.list()) {
- copyDirectory(new File(source, child), new File(destination, child));
+ String[] list = source.list();
+ if (list != null) {
+ for (String child : list) {
+ copyDirectory(new File(source, child), new File(destination, child));
+ }
}
} else {
copyFile(source, destination);
@@ -235,11 +241,14 @@ public abstract class AbstractGitMergeTestCase {
private Iterable<File> getAllContainedFiles(File workingDirectory) {
final Builder<File> builder = ImmutableList.builder();
- for (File containedFile : workingDirectory.listFiles()) {
- if (containedFile.isFile()) {
- builder.add(containedFile);
- } else if (containedFile.isDirectory()) {
- builder.addAll(getAllContainedFiles(containedFile));
+ File[] listFiles = workingDirectory.listFiles();
+ if (listFiles != null) {
+ for (File containedFile : listFiles) {
+ if (containedFile.isFile()) {
+ builder.add(containedFile);
+ } else if (containedFile.isDirectory()) {
+ builder.addAll(getAllContainedFiles(containedFile));
+ }
}
}
return builder.build();
diff --git a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java
index ebd5bafa4..9e649ea2b 100644
--- a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java
+++ b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/AdditiveMergeDiagramTests.java
@@ -10,18 +10,24 @@
*******************************************************************************/
package org.eclipse.emf.compare.diagram.papyrus.tests.merge;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.all;
import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
import static org.eclipse.emf.compare.ConflictKind.REAL;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasConflict;
+import static org.eclipse.emf.compare.DifferenceKind.MOVE;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.isInRealAddAddConflict;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import java.util.Collection;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.conflict.MatchBasedConflictDetector;
import org.eclipse.emf.compare.ide.ui.tests.framework.annotations.ConflictDetectors;
import org.eclipse.emf.compare.ide.ui.tests.git.framework.GitMergeStrategyID;
@@ -34,6 +40,8 @@ import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.lib.Repository;
import org.junit.runner.RunWith;
+import com.google.common.collect.Collections2;
+
@RunWith(GitTestRunner.class)
@GitMergeStrategy(GitMergeStrategyID.MODEL_ADDITIVE)
// FIXME DefaultConflictDetector is broken here
@@ -50,7 +58,8 @@ public class AdditiveMergeDiagramTests {
Comparison comparison = support.compare("wave", "expected", "model.notation");
- assertTrue(all(comparison.getDifferences(), hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
@GitMerge(local = "wired", remote = "wave")
@@ -62,7 +71,8 @@ public class AdditiveMergeDiagramTests {
Comparison comparison = support.compare("wired", "expected", "model.notation");
- assertTrue(all(comparison.getDifferences(), hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
/**
@@ -82,7 +92,18 @@ public class AdditiveMergeDiagramTests {
// package on both sides and it's (currently) impossible to guarantee
// the order in which they will be placed in their parent during a merge
// Let's just check that all diffs are in conflict
- assertTrue(all(comparison.getDifferences(), hasConflict(PSEUDO, REAL)));
+
+ Collection<Diff> diffs = Collections2.filter(comparison.getDifferences(),
+ not(hasDirectOrIndirectConflict(PSEUDO, REAL)));
+ assertEquals(2, diffs.size());
+
+ // Since we cannot be sure of the order of the merged element, this is possible that a side and the
+ // ancestor are placed in the same position and the other side is in another position, resulting in a
+ // move diff which is not in conflict with the expected result. This depend of the checkout branch
+ // when the merge is launched.
+ for (Diff diff : diffs) {
+ assertEquals(MOVE, diff.getKind());
+ }
}
@GitMerge(local = "branch2", remote = "branch1")
@@ -99,6 +120,7 @@ public class AdditiveMergeDiagramTests {
// package on both sides and it's (currently) impossible to guarantee
// the order in which they will be placed in their parent during a merge
// Let's just check that all diffs are in conflict
- assertTrue(all(comparison.getDifferences(), hasConflict(PSEUDO, REAL)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
}
diff --git a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/resourceattachmentchange/move/ResourceAttachmentChangeMoveConflictTests.java b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/resourceattachmentchange/move/ResourceAttachmentChangeMoveConflictTests.java
index 5294116ea..a0c233454 100644
--- a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/resourceattachmentchange/move/ResourceAttachmentChangeMoveConflictTests.java
+++ b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests.git/src/org/eclipse/emf/compare/diagram/papyrus/tests/resourceattachmentchange/move/ResourceAttachmentChangeMoveConflictTests.java
@@ -1,10 +1,14 @@
/*******************************************************************************
- * Copyright (C) 2015 Obeo.
+ * Copyright (C) 2015, 2016 Obeo and others.
*
* 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
+ * Philip Langer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.diagram.papyrus.tests.resourceattachmentchange.move;
@@ -15,95 +19,29 @@ import static com.google.common.collect.Iterables.size;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
import java.io.File;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import org.eclipse.compare.ITypedElement;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IWorkspaceRoot;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.resources.mapping.ModelProvider;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.FileLocator;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.core.runtime.preferences.IEclipsePreferences;
-import org.eclipse.core.runtime.preferences.InstanceScope;
-import org.eclipse.egit.core.Activator;
-import org.eclipse.egit.core.GitCorePreferences;
-import org.eclipse.emf.common.util.BasicMonitor;
import org.eclipse.emf.common.util.EList;
-import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.Conflict;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.DifferenceKind;
-import org.eclipse.emf.compare.EMFCompare;
-import org.eclipse.emf.compare.EMFCompare.Builder;
import org.eclipse.emf.compare.ResourceAttachmentChange;
-import org.eclipse.emf.compare.diagram.internal.extensions.DiagramChange;
import org.eclipse.emf.compare.diagram.papyrus.tests.AbstractGitTestCase;
-import org.eclipse.emf.compare.diagram.papyrus.tests.egit.fixture.GitTestRepository;
-import org.eclipse.emf.compare.diagram.papyrus.tests.egit.fixture.MockSystemReader;
-import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIPlugin;
-import org.eclipse.emf.compare.ide.ui.internal.logical.ComparisonScopeBuilder;
-import org.eclipse.emf.compare.ide.ui.internal.logical.EMFModelProvider;
-import org.eclipse.emf.compare.ide.ui.internal.logical.IdenticalResourceMinimizer;
-import org.eclipse.emf.compare.ide.ui.internal.logical.StorageTypedElement;
-import org.eclipse.emf.compare.ide.ui.internal.logical.SubscriberStorageAccessor;
-import org.eclipse.emf.compare.ide.ui.internal.logical.resolver.CrossReferenceResolutionScope;
-import org.eclipse.emf.compare.ide.ui.internal.logical.resolver.ThreadedModelResolver;
-import org.eclipse.emf.compare.ide.ui.internal.preferences.EMFCompareUIPreferences;
-import org.eclipse.emf.compare.ide.ui.logical.IStorageProvider;
-import org.eclipse.emf.compare.ide.ui.logical.IStorageProviderAccessor;
-import org.eclipse.emf.compare.ide.ui.tests.CompareTestCase;
import org.eclipse.emf.compare.ide.ui.tests.workspace.TestProject;
-import org.eclipse.emf.compare.rcp.internal.extension.impl.EMFCompareBuilderConfigurator;
-import org.eclipse.emf.compare.scope.IComparisonScope;
-import org.eclipse.emf.compare.utils.EMFComparePredicates;
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EPackage;
-import org.eclipse.emf.ecore.InternalEObject;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
-import org.eclipse.emf.ecore.util.EcoreUtil;
-import org.eclipse.gmf.runtime.notation.Diagram;
-import org.eclipse.gmf.runtime.notation.Shape;
-import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jgit.api.ResetCommand.ResetType;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.util.FileUtils;
-import org.eclipse.jgit.util.SystemReader;
-import org.eclipse.team.core.subscribers.Subscriber;
-import org.eclipse.uml2.uml.Class;
-import org.eclipse.uml2.uml.Package;
-import org.eclipse.uml2.uml.PackageableElement;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
-import org.osgi.framework.Bundle;
-
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
/**
* Tests for ResourceAttachmentChange with MOVE kind.
*
* @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
*/
-@SuppressWarnings({"restriction", "nls", "unused" })
+@SuppressWarnings({"nls", "unused" })
public class ResourceAttachmentChangeMoveConflictTests extends AbstractGitTestCase {
/**
@@ -146,13 +84,11 @@ public class ResourceAttachmentChangeMoveConflictTests extends AbstractGitTestCa
// There is a conflict between the move in 2nd commit & the deletion in 3rd commit
Conflict conflict = comparison.getConflicts().get(1);
EList<Diff> differences = conflict.getDifferences();
- assertEquals(3, differences.size());
+ assertEquals(2, differences.size());
assertEquals(1, size(filter(differences,
and(instanceOf(ResourceAttachmentChange.class), ofKind(DifferenceKind.DELETE)))));
assertEquals(1, size(filter(differences,
and(instanceOf(ResourceAttachmentChange.class), ofKind(DifferenceKind.MOVE)))));
- assertEquals(1, size(
- filter(differences, and(instanceOf(DiagramChange.class), ofKind(DifferenceKind.DELETE)))));
testProject1.dispose();
}
@@ -174,13 +110,11 @@ public class ResourceAttachmentChangeMoveConflictTests extends AbstractGitTestCa
// There is a conflict between the move in 2nd commit & the deletion in 3rd commit
Conflict conflict = comparison.getConflicts().get(1);
EList<Diff> differences = conflict.getDifferences();
- assertEquals(3, differences.size());
+ assertEquals(2, differences.size());
assertEquals(1, size(filter(differences,
and(instanceOf(ResourceAttachmentChange.class), ofKind(DifferenceKind.DELETE)))));
assertEquals(1, size(filter(differences,
and(instanceOf(ResourceAttachmentChange.class), ofKind(DifferenceKind.MOVE)))));
- assertEquals(1, size(
- filter(differences, and(instanceOf(DiagramChange.class), ofKind(DifferenceKind.DELETE)))));
testProject1.dispose();
}
diff --git a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/NodeMergeTest.java b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/NodeMergeTest.java
index ee11f05ff..a46dbb481 100644
--- a/plugins/org.eclipse.emf.compare.diagram.papyrus.tests/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/NodeMergeTest.java
+++ b/plugins/org.eclipse.emf.compare.diagram.papyrus.tests/src/org/eclipse/emf/compare/diagram/papyrus/tests/merge/NodeMergeTest.java
@@ -7,19 +7,22 @@
*
* Contributors:
* Obeo - initial API and implementation
- * Philip Langer - bug 482404
+ * Philip Langer - bug 482404, 501864
* Alexandra Buzila - Bug 479449
*******************************************************************************/
package org.eclipse.emf.compare.diagram.papyrus.tests.merge;
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.collect.Iterables.tryFind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasConflict;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueNameMatches;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@@ -27,8 +30,10 @@ import java.io.IOException;
import java.util.regex.Pattern;
import org.eclipse.emf.common.util.BasicMonitor;
+import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.compare.AttributeChange;
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.DifferenceKind;
@@ -1492,12 +1497,40 @@ public class NodeMergeTest extends AbstractTest {
private static Predicate<Diff> isMergedFor3way(final Diff diff) {
return new Predicate<Diff>() {
public boolean apply(Diff input) {
- return input.getConflict() != null && input.getConflict().getKind() == ConflictKind.PSEUDO
- && input.getConflict().getDifferences().contains(diff);
+ final Conflict conflict = getConflictOrConflictOfRefining(input);
+ return diff != null && conflict != null && conflict.getKind() == ConflictKind.PSEUDO
+ && containsDiffOrAnyOfItsRefiningDiffs(diff, conflict);
}
};
}
+ private static Conflict getConflictOrConflictOfRefining(Diff input) {
+ Conflict conflict = null;
+ if (input.getConflict() != null) {
+ conflict = input.getConflict();
+ } else {
+ Optional<Diff> conflictingRefiningDiff = tryFind(input.getRefinedBy(), hasConflict());
+ if (conflictingRefiningDiff.isPresent()) {
+ conflict = conflictingRefiningDiff.get().getConflict();
+ }
+ }
+ return conflict;
+ }
+
+ private static boolean containsDiffOrAnyOfItsRefiningDiffs(Diff diff, Conflict conflict) {
+ return conflict.getDifferences().contains(diff)
+ || containsAny(conflict.getDifferences(), diff.getRefinedBy());
+ }
+
+ private static boolean containsAny(EList<Diff> diffs, EList<Diff> toBeContained) {
+ for (Diff currentDiff : toBeContained) {
+ if (Iterables.contains(diffs, currentDiff)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
protected void registerPostProcessors() {
super.registerPostProcessors();
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/MatchItemProviderSpec.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/MatchItemProviderSpec.java
index 85829049c..c4ec8cc9a 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/MatchItemProviderSpec.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/MatchItemProviderSpec.java
@@ -12,8 +12,11 @@ package org.eclipse.emf.compare.provider.spec;
import static com.google.common.base.Strings.isNullOrEmpty;
+import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.ReferenceChange;
+import org.eclipse.emf.compare.match.MatchOfContainmentReferenceChangeAdapter;
import org.eclipse.emf.compare.match.impl.NotLoadedFragmentMatch;
import org.eclipse.emf.compare.provider.IItemDescriptionProvider;
import org.eclipse.emf.compare.provider.IItemStyledLabelProvider;
@@ -21,6 +24,7 @@ import org.eclipse.emf.compare.provider.ISemanticObjectLabelProvider;
import org.eclipse.emf.compare.provider.MatchItemProvider;
import org.eclipse.emf.compare.provider.utils.ComposedStyledString;
import org.eclipse.emf.compare.provider.utils.IStyledString;
+import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
/**
@@ -71,6 +75,18 @@ public class MatchItemProviderSpec extends MatchItemProvider implements IItemSty
}
if (ret == null) {
+ Adapter adapter = EcoreUtil.getAdapter(match.eAdapters(),
+ MatchOfContainmentReferenceChangeAdapter.class);
+ if (adapter instanceof MatchOfContainmentReferenceChangeAdapter) {
+ ReferenceChange referenceChange = ((MatchOfContainmentReferenceChangeAdapter)adapter)
+ .getReferenceChange();
+ if (referenceChange != null) {
+ ret = itemDelegator.getImage(referenceChange.getValue());
+ }
+ }
+ }
+
+ if (ret == null) {
ret = super.getImage(object);
}
@@ -106,7 +122,23 @@ public class MatchItemProviderSpec extends MatchItemProvider implements IItemSty
ret += " (" + name + ")"; //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
- ret = super.getText(object);
+ Adapter matchAdapter = EcoreUtil.getAdapter(match.eAdapters(),
+ MatchOfContainmentReferenceChangeAdapter.class);
+ if (matchAdapter instanceof MatchOfContainmentReferenceChangeAdapter) {
+ ReferenceChange referenceChange = ((MatchOfContainmentReferenceChangeAdapter)matchAdapter)
+ .getReferenceChange();
+ Adapter rcAdapter = null;
+ if (referenceChange != null) {
+ rcAdapter = EcoreUtil.getAdapter(referenceChange.eAdapters(),
+ ReferenceChangeItemProviderSpec.class);
+ }
+ if (rcAdapter instanceof ReferenceChangeItemProviderSpec) {
+ ret = ((ReferenceChangeItemProviderSpec)rcAdapter).getValueText(referenceChange);
+ }
+ }
+ if (isNullOrEmpty(ret)) {
+ ret = super.getText(object);
+ }
}
}
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/OverlayImageProvider.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/OverlayImageProvider.java
index d0e5845ea..11eb887a1 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/OverlayImageProvider.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/OverlayImageProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2015 Obeo.
+ * Copyright (c) 2012, 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
@@ -11,6 +11,9 @@
package org.eclipse.emf.compare.provider.spec;
import static com.google.common.collect.Lists.newArrayList;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.canBeConsideredAsPseudoConflicting;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
import java.util.Collection;
import java.util.List;
@@ -18,8 +21,6 @@ import java.util.List;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.util.ResourceLocator;
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.DifferenceKind;
import org.eclipse.emf.compare.DifferenceSource;
@@ -168,25 +169,31 @@ public class OverlayImageProvider {
// Nothing here has to be externalized
@SuppressWarnings("nls")
private String getThreeWayOverlay(final Diff diff) {
- final Conflict conflict = diff.getConflict();
final DifferenceKind diffKind = diff.getKind();
final DifferenceSource source = diff.getSource();
- String path = "";
- if (conflict != null) {
- if (conflict.getKind() == ConflictKind.PSEUDO) {
- path += "p";
+
+ StringBuilder path = new StringBuilder();
+ if (hasDirectOrIndirectConflict(REAL).apply(diff)) {
+ // The diff or one of its refining diffs are in a pseudo conflict
+ path.append("conf");
+ if (source == DifferenceSource.RIGHT) {
+ path.append("r_");
}
- path += "conf";
+ } else if (canBeConsideredAsPseudoConflicting().apply(diff)) {
+ // If the diff is not a refined diff and are in a pseudo conflict
+ // Or if the diff is a refined diff that are not in a direct pseudo conflict, but all its refining
+ // diffs are in pseudo conflicts
+ path.append("pconf");
if (source == DifferenceSource.RIGHT) {
- path += "r_";
+ path.append("r_");
}
} else {
switch (source) {
case LEFT:
- path += "r_out";
+ path.append("r_out");
break;
case RIGHT:
- path += "r_in";
+ path.append("r_in");
break;
default:
// Cannot happen ... for now
@@ -196,21 +203,21 @@ public class OverlayImageProvider {
switch (diffKind) {
case ADD:
- path += ADD_OV;
+ path.append(ADD_OV);
break;
case DELETE:
- path += DEL_OV;
+ path.append(DEL_OV);
break;
case CHANGE:
// fallthrough
case MOVE:
- path += CHG_OV;
+ path.append(CHG_OV);
break;
default:
// Cannot happen ... for now
break;
}
- return path;
+ return path.toString();
}
/**
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/ReferenceChangeItemProviderSpec.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/ReferenceChangeItemProviderSpec.java
index 2fc853c5f..ac849b6fb 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/ReferenceChangeItemProviderSpec.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/provider/spec/ReferenceChangeItemProviderSpec.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2015 Obeo.
+ * Copyright (c) 2012, 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
@@ -69,6 +69,19 @@ public class ReferenceChangeItemProviderSpec extends ReferenceChangeItemProvider
/**
* {@inheritDoc}
*
+ * @see org.eclipse.emf.edit.provider.ItemProviderAdapter#isAdapterForType(Object)
+ */
+ @Override
+ public boolean isAdapterForType(Object type) {
+ if (type == ReferenceChangeItemProviderSpec.class) {
+ return true;
+ }
+ return super.isAdapterForType(type);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.eclipse.emf.compare.provider.ReferenceChangeItemProvider#getText(java.lang.Object)
*/
@Override
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AbstractTooltipProvider.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AbstractTooltipProvider.java
index ce0240153..ba8111d91 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AbstractTooltipProvider.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AbstractTooltipProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015 Obeo and others.
+ * Copyright (c) 2015, 2016 Obeo and others.
* 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
@@ -20,6 +20,7 @@ import org.eclipse.emf.compare.ResourceAttachmentChange;
import org.eclipse.emf.compare.ResourceLocationChange;
import org.eclipse.emf.compare.internal.merge.MergeMode;
import org.eclipse.emf.compare.provider.ISemanticObjectLabelProvider;
+import org.eclipse.emf.compare.provider.ITooltipLabelProvider;
import org.eclipse.emf.compare.utils.MatchUtil;
import org.eclipse.emf.compare.utils.ReferenceUtil;
import org.eclipse.emf.ecore.EObject;
@@ -34,7 +35,7 @@ import org.eclipse.emf.edit.provider.IItemLabelProvider;
* The parametric type of the class
* @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a>
*/
-public abstract class AbstractTooltipProvider<T extends Diff> extends AdapterImpl {
+public abstract class AbstractTooltipProvider<T extends Diff> extends AdapterImpl implements ITooltipLabelProvider {
/**
* The line separator used to compute tooltips.
@@ -52,6 +53,19 @@ public abstract class AbstractTooltipProvider<T extends Diff> extends AdapterImp
protected IItemLabelProvider labelProvider;
/**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.common.notify.impl.AdapterImpl#isAdapterForType(Object)
+ */
+ @Override
+ public boolean isAdapterForType(Object type) {
+ if (type == ITooltipLabelProvider.class) {
+ return true;
+ }
+ return super.isAdapterForType(type);
+ }
+
+ /**
* Create the final tooltip for an accepted change which lead to a modification of the left side.
*
* @param value
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AttributeChangeTooltipProvider.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AttributeChangeTooltipProvider.java
index b3cf69b7e..e7b8d518e 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AttributeChangeTooltipProvider.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/AttributeChangeTooltipProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015 Obeo.
+ * Copyright (c) 2015, 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
@@ -15,7 +15,6 @@ import static org.eclipse.emf.compare.utils.ReferenceUtil.safeEGet;
import org.eclipse.emf.compare.AttributeChange;
import org.eclipse.emf.compare.internal.merge.MergeMode;
-import org.eclipse.emf.compare.provider.ITooltipLabelProvider;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
@@ -26,7 +25,7 @@ import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
*
* @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a>
*/
-public class AttributeChangeTooltipProvider extends AbstractTooltipProvider<AttributeChange> implements ITooltipLabelProvider {
+public class AttributeChangeTooltipProvider extends AbstractTooltipProvider<AttributeChange> {
/**
* The constructor.
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/FeatureMapChangeTooltipProvider.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/FeatureMapChangeTooltipProvider.java
index f2a7ac697..5015f93ce 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/FeatureMapChangeTooltipProvider.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/FeatureMapChangeTooltipProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015 Obeo.
+ * Copyright (c) 2015, 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
@@ -12,7 +12,6 @@ package org.eclipse.emf.compare.tooltip;
import org.eclipse.emf.compare.FeatureMapChange;
import org.eclipse.emf.compare.internal.merge.MergeMode;
-import org.eclipse.emf.compare.provider.ITooltipLabelProvider;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
@@ -21,7 +20,7 @@ import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
*
* @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a>
*/
-public class FeatureMapChangeTooltipProvider extends AbstractTooltipProvider<FeatureMapChange> implements ITooltipLabelProvider {
+public class FeatureMapChangeTooltipProvider extends AbstractTooltipProvider<FeatureMapChange> {
/**
* The constructor.
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ReferenceChangeTooltipProvider.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ReferenceChangeTooltipProvider.java
index 576efc6a3..3305473b5 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ReferenceChangeTooltipProvider.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ReferenceChangeTooltipProvider.java
@@ -16,7 +16,6 @@ import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.ReferenceChange;
import org.eclipse.emf.compare.internal.merge.MergeMode;
-import org.eclipse.emf.compare.provider.ITooltipLabelProvider;
import org.eclipse.emf.compare.utils.ReferenceUtil;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
@@ -27,7 +26,7 @@ import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
*
* @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a>
*/
-public class ReferenceChangeTooltipProvider extends AbstractTooltipProvider<ReferenceChange> implements ITooltipLabelProvider {
+public class ReferenceChangeTooltipProvider extends AbstractTooltipProvider<ReferenceChange> {
/**
* The constructor.
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceAttachmentChangeTooltipProvider.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceAttachmentChangeTooltipProvider.java
index 08fdf7bec..4510b1669 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceAttachmentChangeTooltipProvider.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceAttachmentChangeTooltipProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015 Obeo.
+ * Copyright (c) 2015, 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
@@ -15,7 +15,6 @@ import static org.eclipse.emf.compare.internal.EMFCompareEditMessages.getString;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.ResourceAttachmentChange;
import org.eclipse.emf.compare.internal.merge.MergeMode;
-import org.eclipse.emf.compare.provider.ITooltipLabelProvider;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
@@ -26,7 +25,7 @@ import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
*
* @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a>
*/
-public class ResourceAttachmentChangeTooltipProvider extends AbstractTooltipProvider<ResourceAttachmentChange> implements ITooltipLabelProvider {
+public class ResourceAttachmentChangeTooltipProvider extends AbstractTooltipProvider<ResourceAttachmentChange> {
/**
* The constructor.
diff --git a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceLocationChangeTooltipProvider.java b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceLocationChangeTooltipProvider.java
index 09f7056cf..fd3a09971 100644
--- a/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceLocationChangeTooltipProvider.java
+++ b/plugins/org.eclipse.emf.compare.edit/src/org/eclipse/emf/compare/tooltip/ResourceLocationChangeTooltipProvider.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2015 Obeo.
+ * Copyright (c) 2015, 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
@@ -13,7 +13,6 @@ package org.eclipse.emf.compare.tooltip;
import org.eclipse.emf.compare.DifferenceKind;
import org.eclipse.emf.compare.ResourceLocationChange;
import org.eclipse.emf.compare.internal.merge.MergeMode;
-import org.eclipse.emf.compare.provider.ITooltipLabelProvider;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
@@ -22,7 +21,7 @@ import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
*
* @author <a href="mailto:mathieu.cartaud@obeo.fr">Mathieu Cartaud</a>
*/
-public class ResourceLocationChangeTooltipProvider extends AbstractTooltipProvider<ResourceLocationChange> implements ITooltipLabelProvider {
+public class ResourceLocationChangeTooltipProvider extends AbstractTooltipProvider<ResourceLocationChange> {
/**
* The constructor.
diff --git a/plugins/org.eclipse.emf.compare.ide.ui.tests.git.framework/src/org/eclipse/emf/compare/ide/ui/tests/git/framework/internal/statements/InternalGitTestSupport.java b/plugins/org.eclipse.emf.compare.ide.ui.tests.git.framework/src/org/eclipse/emf/compare/ide/ui/tests/git/framework/internal/statements/InternalGitTestSupport.java
index 6488d8908..6a383c4fa 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui.tests.git.framework/src/org/eclipse/emf/compare/ide/ui/tests/git/framework/internal/statements/InternalGitTestSupport.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui.tests.git.framework/src/org/eclipse/emf/compare/ide/ui/tests/git/framework/internal/statements/InternalGitTestSupport.java
@@ -151,13 +151,16 @@ public class InternalGitTestSupport {
* @return The path to the .git folder
*/
private File findGitDir(File file) {
- for (File child : file.listFiles()) {
- if (child.isDirectory() && child.getName().equals(".git")) { //$NON-NLS-1$
- return child;
- } else if (child.isDirectory()) {
- File findGitDir = findGitDir(child);
- if (findGitDir != null) {
- return findGitDir;
+ File[] listFiles = file.listFiles();
+ if (listFiles != null) {
+ for (File child : listFiles) {
+ if (child.isDirectory() && child.getName().equals(".git")) { //$NON-NLS-1$
+ return child;
+ } else if (child.isDirectory()) {
+ File findGitDir = findGitDir(child);
+ if (findGitDir != null) {
+ return findGitDir;
+ }
}
}
}
@@ -178,12 +181,15 @@ public class InternalGitTestSupport {
*/
private void importProjects(File file)
throws InvocationTargetException, InterruptedException, CoreException {
- for (File child : file.listFiles()) {
- if (child.isDirectory() && !child.getName().equals(METADATA_FOLDER)
- && !child.getName().equals(".git")) { //$NON-NLS-1$
- importProjects(child);
- } else if (child.getName().equals(".project")) { //$NON-NLS-1$
- importProject(child);
+ File[] listFiles = file.listFiles();
+ if (listFiles != null) {
+ for (File child : listFiles) {
+ if (child.isDirectory() && !child.getName().equals(METADATA_FOLDER)
+ && !child.getName().equals(".git")) { //$NON-NLS-1$
+ importProjects(child);
+ } else if (child.getName().equals(".project")) { //$NON-NLS-1$
+ importProject(child);
+ }
}
}
}
@@ -282,9 +288,12 @@ public class InternalGitTestSupport {
Activator.getDefault().getRepositoryCache().clear();
File file = new File(workspaceRoot.getLocation().toOSString());
- for (File child : file.listFiles()) {
- if (!child.getName().equals(METADATA_FOLDER)) {
- FileUtils.delete(child, FileUtils.RECURSIVE | FileUtils.RETRY);
+ File[] listFiles = file.listFiles();
+ if (listFiles != null) {
+ for (File child : listFiles) {
+ if (!child.getName().equals(METADATA_FOLDER)) {
+ FileUtils.delete(child, FileUtils.RECURSIVE | FileUtils.RETRY);
+ }
}
}
}
@@ -319,9 +328,12 @@ public class InternalGitTestSupport {
}
File file = new File(ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString());
- for (File child : file.listFiles()) {
- if (!child.getName().equals(METADATA_FOLDER)) {
- FileUtils.delete(child, FileUtils.RECURSIVE | FileUtils.RETRY);
+ File[] listFiles = file.listFiles();
+ if (listFiles != null) {
+ for (File child : listFiles) {
+ if (!child.getName().equals(METADATA_FOLDER)) {
+ FileUtils.delete(child, FileUtils.RECURSIVE | FileUtils.RETRY);
+ }
}
}
}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java b/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java
index a5114bdef..28d1147b9 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/AdditiveMergeTests.java
@@ -8,8 +8,11 @@
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.tests.merge;
+import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.all;
import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.isInRealAddAddConflict;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -24,7 +27,6 @@ import org.eclipse.emf.compare.ide.ui.tests.git.framework.GitTestSupport;
import org.eclipse.emf.compare.ide.ui.tests.git.framework.annotations.GitInput;
import org.eclipse.emf.compare.ide.ui.tests.git.framework.annotations.GitMerge;
import org.eclipse.emf.compare.ide.ui.tests.git.framework.annotations.GitMergeStrategy;
-import org.eclipse.emf.compare.utils.EMFComparePredicates;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.lib.Repository;
import org.junit.runner.RunWith;
@@ -43,7 +45,8 @@ public class AdditiveMergeTests {
Comparison comparison = support.compare("branch1", "expected", "network.ecore");
- assertTrue(all(comparison.getDifferences(), EMFComparePredicates.hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
@GitMerge(local = "branch2", remote = "branch1")
@@ -55,7 +58,8 @@ public class AdditiveMergeTests {
Comparison comparison = support.compare("branch2", "expected", "network.ecore");
- assertTrue(all(comparison.getDifferences(), EMFComparePredicates.hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
@GitMerge(local = "branch1", remote = "branch2")
@@ -67,7 +71,8 @@ public class AdditiveMergeTests {
Comparison comparison = support.compare("branch1", "expected", "network.uml");
- assertTrue(all(comparison.getDifferences(), EMFComparePredicates.hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
@GitMerge(local = "branch2", remote = "branch1")
@@ -79,6 +84,7 @@ public class AdditiveMergeTests {
Comparison comparison = support.compare("branch2", "expected", "network.uml");
- assertTrue(all(comparison.getDifferences(), EMFComparePredicates.hasConflict(PSEUDO)));
+ assertTrue(all(comparison.getDifferences(),
+ or(hasDirectOrIndirectConflict(PSEUDO), isInRealAddAddConflict())));
}
}
diff --git a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java
index f07f26307..9c2a507c4 100644
--- a/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java
+++ b/plugins/org.eclipse.emf.compare.ide.ui/src/org/eclipse/emf/compare/ide/ui/internal/structuremergeviewer/EMFCompareStructureMergeViewer.java
@@ -120,6 +120,7 @@ import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.Stru
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl.CascadingDifferencesFilter;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.StructureMergeViewerGrouper;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.provider.TreeItemProviderAdapterFactorySpec;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.match.MatchOfContainmentReferenceChangeProcessor;
import org.eclipse.emf.compare.rcp.ui.internal.util.SWTUtil;
import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.filters.IDifferenceFilterChange;
import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroup;
@@ -1208,6 +1209,8 @@ public class EMFCompareStructureMergeViewer extends AbstractStructuredViewerWrap
labelProvider.getRightImage(input));
compareResult.eAdapters().add(sideLabelProvider);
}
+ // Bug 501569: The cascading filter does not hide merged cascading diffs
+ new MatchOfContainmentReferenceChangeProcessor().execute(compareResult);
}
/**
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.compare.rcp.ui.tests/META-INF/MANIFEST.MF
index 1d85c0799..db1261ff5 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui.tests/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/META-INF/MANIFEST.MF
@@ -11,7 +11,9 @@ Require-Bundle: org.eclipse.core.runtime,
org.eclipse.emf.compare.edit;bundle-version="3.0.0",
org.eclipse.emf.compare.tests;bundle-version="2.1.0",
org.eclipse.emf.compare.rcp;bundle-version="2.1.0",
- org.eclipse.emf.compare.rcp.ui;bundle-version="3.0.0"
+ org.eclipse.emf.compare.rcp.ui;bundle-version="3.0.0",
+ org.eclipse.jface,
+ org.eclipse.emf.compare.ide.ui.tests.framework
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-Vendor: %providerName
Import-Package: com.google.common.base;version="[11.0.0,16.0.0)",
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/MatchAccessorTest.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/MatchAccessorTest.java
new file mode 100644
index 000000000..781e2dd38
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/MatchAccessorTest.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 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.rcp.ui.tests.contentmergeviewer.accessor.match;
+
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.addedToReference;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.removedFromReference;
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.EMFCompare;
+import org.eclipse.emf.compare.EMFCompare.Builder;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.rcp.internal.extension.impl.EMFCompareBuilderConfigurator;
+import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement;
+import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.accessor.factory.impl.MatchAccessorFactory;
+import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.accessor.impl.MatchAccessor;
+import org.eclipse.emf.compare.rcp.ui.internal.mergeviewer.item.impl.MergeViewerItem;
+import org.eclipse.emf.compare.rcp.ui.internal.util.MergeViewerUtil;
+import org.eclipse.emf.compare.rcp.ui.tests.contentmergeviewer.accessor.match.data.MatchAccessorInputData;
+import org.eclipse.emf.compare.scope.DefaultComparisonScope;
+import org.eclipse.emf.compare.scope.IComparisonScope;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterators;
+
+/**
+ * Tests for {@link MatchAccessor}.
+ *
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+@SuppressWarnings("restriction")
+public class MatchAccessorTest {
+
+ private final static MatchAccessorInputData inputData = new MatchAccessorInputData();
+
+ private final static ComposedAdapterFactory fAdapterFactory = new ComposedAdapterFactory(
+ ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
+
+ private static Comparison comparison;
+
+ @BeforeClass
+ public static void beforeClass() throws IOException {
+ fAdapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());
+ fAdapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory());
+ final Resource leftResource = inputData.getLeft();
+ final Resource rightResource = inputData.getRight();
+ final Resource originResource = inputData.getOrigin();
+
+ final IComparisonScope scope = new DefaultComparisonScope(leftResource, rightResource,
+ originResource);
+ final Builder comparisonBuilder = EMFCompare.builder();
+ EMFCompareBuilderConfigurator.createDefault().configure(comparisonBuilder);
+ comparison = comparisonBuilder.build().compare(scope);
+ }
+
+ @Test
+ public void testEClassifiersAdd() {
+ final List<Diff> differences = comparison.getDifferences();
+
+ final Predicate<? super Diff> item = addedToReference("extlibrary", "eClassifiers",
+ "extlibrary.Item");
+ final Diff itemDiff = Iterators.find(differences.iterator(), item);
+ final EObject itemValue = (EObject)MergeViewerUtil.getDiffValue(itemDiff);
+ final Match itemMatch = comparison.getMatch(itemValue);
+
+ final MatchAccessorFactory factory = new MatchAccessorFactory();
+ final ITypedElement leftTypedElement = factory.createLeft(fAdapterFactory, itemMatch);
+ final ITypedElement rightTypedElement = factory.createRight(fAdapterFactory, itemMatch);
+ final ITypedElement originTypedElement = factory.createAncestor(fAdapterFactory, itemMatch);
+
+ if (leftTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)leftTypedElement).getDiff();
+ assertEquals(diff, itemDiff);
+ }
+ if (rightTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)rightTypedElement).getDiff();
+ assertEquals(diff, itemDiff);
+ }
+ if (originTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)originTypedElement).getDiff();
+ assertEquals(diff, itemDiff);
+ }
+ }
+
+ @Test
+ public void testEStructuralFeaturesDelete() {
+ final List<Diff> differences = comparison.getDifferences();
+
+ final Predicate<? super Diff> title = removedFromReference("extlibrary.Book", "eStructuralFeatures",
+ "extlibrary.Book.title");
+ final Diff titleDiff = Iterators.find(differences.iterator(), title);
+ final EObject titleValue = (EObject)MergeViewerUtil.getDiffValue(titleDiff);
+ final Match titleMatch = comparison.getMatch(titleValue);
+
+ final MatchAccessorFactory factory = new MatchAccessorFactory();
+ final ITypedElement leftTypedElement = factory.createLeft(fAdapterFactory, titleMatch);
+ final ITypedElement rightTypedElement = factory.createRight(fAdapterFactory, titleMatch);
+ final ITypedElement originTypedElement = factory.createAncestor(fAdapterFactory, titleMatch);
+
+ if (leftTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)leftTypedElement).getDiff();
+ assertEquals(diff, titleDiff);
+ }
+ if (rightTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)rightTypedElement).getDiff();
+ assertEquals(diff, titleDiff);
+ }
+ if (originTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)originTypedElement).getDiff();
+ assertEquals(diff, titleDiff);
+ }
+ }
+
+ @Test
+ public void testELiteralsMultipleDelete() {
+ final List<Diff> differences = comparison.getDifferences();
+ final MatchAccessorFactory factory = new MatchAccessorFactory();
+
+ final Predicate<? super Diff> encyclopedia = removedFromReference("extlibrary.BookCategory",
+ "eLiterals", "extlibrary.BookCategory.Encyclopedia");
+ final Diff encyclopediaDiff = Iterators.find(differences.iterator(), encyclopedia);
+ final EObject encyclopediaValue = (EObject)MergeViewerUtil.getDiffValue(encyclopediaDiff);
+ final Match encyclopediaMatch = comparison.getMatch(encyclopediaValue);
+
+ final ITypedElement encyclopediaLeftTypedElement = factory.createLeft(fAdapterFactory,
+ encyclopediaMatch);
+ final ITypedElement encyclopediaRightTypedElement = factory.createRight(fAdapterFactory,
+ encyclopediaMatch);
+ final ITypedElement encyclopediaOriginTypedElement = factory.createAncestor(fAdapterFactory,
+ encyclopediaMatch);
+
+ if (encyclopediaLeftTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)encyclopediaLeftTypedElement).getDiff();
+ assertEquals(diff, encyclopediaDiff);
+ }
+ if (encyclopediaRightTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)encyclopediaRightTypedElement).getDiff();
+ assertEquals(diff, encyclopediaDiff);
+ }
+ if (encyclopediaOriginTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)encyclopediaOriginTypedElement).getDiff();
+ assertEquals(diff, encyclopediaDiff);
+ }
+
+ final Predicate<? super Diff> dictionary = removedFromReference("extlibrary.BookCategory",
+ "eLiterals", "extlibrary.BookCategory.Dictionary");
+ final Diff dictionaryDiff = Iterators.find(differences.iterator(), dictionary);
+ final EObject dictionaryValue = (EObject)MergeViewerUtil.getDiffValue(dictionaryDiff);
+ final Match dictionaryMatch = comparison.getMatch(dictionaryValue);
+
+ final ITypedElement dictionaryLeftTypedElement = factory.createLeft(fAdapterFactory, dictionaryMatch);
+ final ITypedElement dictionaryRightTypedElement = factory.createRight(fAdapterFactory,
+ dictionaryMatch);
+ final ITypedElement dictionaryOriginTypedElement = factory.createAncestor(fAdapterFactory,
+ dictionaryMatch);
+
+ if (dictionaryLeftTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)dictionaryLeftTypedElement).getDiff();
+ assertEquals(diff, dictionaryDiff);
+ }
+ if (dictionaryRightTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)dictionaryRightTypedElement).getDiff();
+ assertEquals(diff, dictionaryDiff);
+ }
+ if (dictionaryOriginTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)dictionaryOriginTypedElement).getDiff();
+ assertEquals(diff, dictionaryDiff);
+ }
+ }
+
+ @Test
+ public void testEStructuralFeaturesMultipleAdd() {
+ final List<Diff> differences = comparison.getDifferences();
+ final MatchAccessorFactory factory = new MatchAccessorFactory();
+
+ final Predicate<? super Diff> borrowed = addedToReference("extlibrary.Borrower",
+ "eStructuralFeatures", "extlibrary.Borrower.borrowed");
+ final Diff borrowedDiff = Iterators.find(differences.iterator(), borrowed);
+ final EObject borrowedValue = (EObject)MergeViewerUtil.getDiffValue(borrowedDiff);
+ final Match borrowedMatch = comparison.getMatch(borrowedValue);
+
+ final ITypedElement borrowedLeftTypedElement = factory.createLeft(fAdapterFactory, borrowedMatch);
+ final ITypedElement borrowedRightTypedElement = factory.createRight(fAdapterFactory, borrowedMatch);
+ final ITypedElement borrowedOriginTypedElement = factory.createAncestor(fAdapterFactory,
+ borrowedMatch);
+
+ if (borrowedLeftTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)borrowedLeftTypedElement).getDiff();
+ assertEquals(diff, borrowedDiff);
+ }
+ if (borrowedRightTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)borrowedRightTypedElement).getDiff();
+ assertEquals(diff, borrowedDiff);
+ }
+ if (borrowedOriginTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)borrowedOriginTypedElement).getDiff();
+ assertEquals(diff, borrowedDiff);
+ }
+
+ final Predicate<? super Diff> containmentBorrowed = addedToReference("extlibrary.Borrower",
+ "eStructuralFeatures", "extlibrary.Borrower.containmentBorrowed");
+ final Diff containmentBorrowedDiff = Iterators.find(differences.iterator(), containmentBorrowed);
+ final EObject containmentBorrowedValue = (EObject)MergeViewerUtil
+ .getDiffValue(containmentBorrowedDiff);
+ final Match containmentBorrowedMatch = comparison.getMatch(containmentBorrowedValue);
+
+ final ITypedElement containmentBorrowedLeftTypedElement = factory.createLeft(fAdapterFactory,
+ containmentBorrowedMatch);
+ final ITypedElement containmentBorrowedRightTypedElement = factory.createRight(fAdapterFactory,
+ containmentBorrowedMatch);
+ final ITypedElement containmentBorrowedOriginTypedElement = factory.createAncestor(fAdapterFactory,
+ containmentBorrowedMatch);
+
+ if (containmentBorrowedLeftTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)containmentBorrowedLeftTypedElement).getDiff();
+ assertEquals(diff, containmentBorrowedDiff);
+ }
+ if (containmentBorrowedRightTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)containmentBorrowedRightTypedElement).getDiff();
+ assertEquals(diff, containmentBorrowedDiff);
+ }
+ if (containmentBorrowedOriginTypedElement instanceof MergeViewerItem) {
+ Diff diff = ((MergeViewerItem)containmentBorrowedOriginTypedElement).getDiff();
+ assertEquals(diff, containmentBorrowedDiff);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/MatchAccessorInputData.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/MatchAccessorInputData.java
new file mode 100644
index 000000000..83415adec
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/MatchAccessorInputData.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 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.rcp.ui.tests.contentmergeviewer.accessor.match.data;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.tests.edit.data.ResourceScopeProvider;
+import org.eclipse.emf.compare.tests.framework.AbstractInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+
+public class MatchAccessorInputData extends AbstractInputData implements ResourceScopeProvider {
+
+ public Resource getLeft() throws IOException {
+ return loadFromClassLoader("left.ecore");
+ }
+
+ public Resource getRight() throws IOException {
+ return loadFromClassLoader("right.ecore");
+ }
+
+ public Resource getOrigin() throws IOException {
+ return loadFromClassLoader("origin.ecore");
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/left.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/left.ecore
new file mode 100644
index 000000000..b26859bfa
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/left.ecore
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmi:id="_14sTEG60EeGkd4g88tZXfA" name="extlibrary" nsURI="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0"
+ nsPrefix="extlib">
+ <eClassifiers xsi:type="ecore:EClass" xmi:id="_146VgG60EeGkd4g88tZXfA" name="Book">
+ <eStructuralFeatures xsi:type="ecore:EAttribute" xmi:id="_146VgW60EeGkd4g88tZXfA"
+ name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+ </eClassifiers>
+ <eClassifiers xsi:type="ecore:EEnum" xmi:id="_15F7sG60EeGkd4g88tZXfA" name="BookCategory">
+ <eLiterals xmi:id="_XID4MG9IEeG7V_vNzpYwOw" name="Encyclopedia" value="3" literal="Encyclopedia"/>
+ <eLiterals xmi:id="_XIEfQG9IEeG7V_vNzpYwOw" name="Dictionary" value="4"/>
+ </eClassifiers>
+ <eClassifiers xsi:type="ecore:EClass" name="Borrowable" abstract="true" interface="true"/>
+ <eClassifiers xsi:type="ecore:EClass" name="Borrower"/>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/origin.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/origin.ecore
new file mode 100644
index 000000000..b26859bfa
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/origin.ecore
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmi:id="_14sTEG60EeGkd4g88tZXfA" name="extlibrary" nsURI="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0"
+ nsPrefix="extlib">
+ <eClassifiers xsi:type="ecore:EClass" xmi:id="_146VgG60EeGkd4g88tZXfA" name="Book">
+ <eStructuralFeatures xsi:type="ecore:EAttribute" xmi:id="_146VgW60EeGkd4g88tZXfA"
+ name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+ </eClassifiers>
+ <eClassifiers xsi:type="ecore:EEnum" xmi:id="_15F7sG60EeGkd4g88tZXfA" name="BookCategory">
+ <eLiterals xmi:id="_XID4MG9IEeG7V_vNzpYwOw" name="Encyclopedia" value="3" literal="Encyclopedia"/>
+ <eLiterals xmi:id="_XIEfQG9IEeG7V_vNzpYwOw" name="Dictionary" value="4"/>
+ </eClassifiers>
+ <eClassifiers xsi:type="ecore:EClass" name="Borrowable" abstract="true" interface="true"/>
+ <eClassifiers xsi:type="ecore:EClass" name="Borrower"/>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/right.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/right.ecore
new file mode 100644
index 000000000..943f732da
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/contentmergeviewer/accessor/match/data/right.ecore
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmi:id="_14sTEG60EeGkd4g88tZXfA" name="extlibrary" nsURI="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0"
+ nsPrefix="extlib">
+ <eClassifiers xsi:type="ecore:EClass" xmi:id="_146VgG60EeGkd4g88tZXfA" name="Book"/>
+ <eClassifiers xsi:type="ecore:EEnum" xmi:id="_15F7sG60EeGkd4g88tZXfA" name="BookCategory"/>
+ <eClassifiers xsi:type="ecore:EClass" name="Item" abstract="true"/>
+ <eClassifiers xsi:type="ecore:EClass" name="Borrowable" abstract="true" interface="true"/>
+ <eClassifiers xsi:type="ecore:EClass" name="Borrower">
+ <eStructuralFeatures xsi:type="ecore:EReference" name="borrowed" upperBound="-1"
+ eType="#//Borrowable"/>
+ <eStructuralFeatures xsi:type="ecore:EReference" name="containmentBorrowed" upperBound="-1"
+ eType="#//Borrowable" containment="true"/>
+ </eClassifiers>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/CascadingDiffFilterTest.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/CascadingDiffFilterTest.java
new file mode 100644
index 000000000..cc5a92e01
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/CascadingDiffFilterTest.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 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.rcp.ui.tests.structuremergeviewer.filters;
+
+import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
+import static org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups.provider.AbstractTestTreeNodeItemProviderAdapter.getComparison;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.CompareFactory;
+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.Match;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl.CascadingDifferencesFilter;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.BasicDifferenceGroupImpl;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.DiffNode;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.MatchNode;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.MatchResourceNode;
+import org.eclipse.emf.compare.tests.edit.data.ResourceScopeProvider;
+import org.eclipse.emf.compare.tests.framework.AbstractInputData;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
+import org.eclipse.emf.edit.tree.TreePackage;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.base.Predicates;
+
+@SuppressWarnings("restriction")
+public class CascadingDiffFilterTest {
+
+ private Comparison comp;
+
+ private CascadingDifferencesFilter filter;
+
+ private TestECrossReferenceAdapter crossReferenceAdapter;
+
+ /**
+ * Basic test to make sure the 1st addition is not filtered and its children are.
+ */
+ @Test
+ public void testWithoutRefiningDiffs() {
+ BasicDifferenceGroupImpl group = new BasicDifferenceGroupImpl(comp, Predicates.alwaysTrue(),
+ crossReferenceAdapter);
+ group.buildSubTree();
+ assertEquals(2, group.getChildren().size());
+ MatchNode rootNode = (MatchNode)group.getChildren().get(0);
+ assertTrue(group.getChildren().get(1) instanceof MatchResourceNode);
+
+ assertEquals(1, rootNode.getChildren().size());
+ MatchNode cNode = (MatchNode)rootNode.getChildren().get(0);
+ assertEquals(2, cNode.getChildren().size());
+
+ DiffNode addClassNode = (DiffNode)cNode.getChildren().get(0);
+ assertFalse(filter.getPredicateWhenSelected().apply(addClassNode));
+ assertFalse(filter.getPredicateWhenUnselected().apply(addClassNode));
+
+ MatchNode attNode = (MatchNode)cNode.getChildren().get(1);
+ assertEquals(1, attNode.getChildren().size());
+
+ DiffNode addAttNode = (DiffNode)attNode.getChildren().get(0);
+ assertTrue(filter.getPredicateWhenSelected().apply(addAttNode));
+ assertFalse(filter.getPredicateWhenUnselected().apply(addAttNode));
+ }
+
+ /**
+ * A non-conflicting cascading refined diff is not filtered if it has a real conflict diff among its
+ * refining diffs.
+ */
+ @Test
+ public void testWithRealConflictRefiningDiffs() {
+ Match rootMatch = comp.getMatches().get(0);
+ Match cMatch = rootMatch.getSubmatches().get(0);
+ Match attMatch = cMatch.getSubmatches().get(0);
+ Diff attAddition = cMatch.getDifferences().get(0);
+
+ // Create a refinedDiff refined by the att addition
+ createRefinedDiff(attMatch, attAddition);
+
+ // Create a real conflict on the refining diff
+ createConflict(attAddition, REAL);
+
+ BasicDifferenceGroupImpl group = new BasicDifferenceGroupImpl(comp, Predicates.alwaysTrue(),
+ crossReferenceAdapter);
+ group.buildSubTree();
+ assertEquals(2, group.getChildren().size());
+ MatchNode rootNode = (MatchNode)group.getChildren().get(0);
+ assertTrue(group.getChildren().get(1) instanceof MatchResourceNode);
+
+ assertEquals(1, rootNode.getChildren().size());
+ MatchNode cNode = (MatchNode)rootNode.getChildren().get(0);
+ assertEquals(2, cNode.getChildren().size());
+
+ DiffNode addClassNode = (DiffNode)cNode.getChildren().get(0);
+ assertFalse(filter.getPredicateWhenSelected().apply(addClassNode));
+ assertFalse(filter.getPredicateWhenUnselected().apply(addClassNode));
+
+ MatchNode attNode = (MatchNode)cNode.getChildren().get(1);
+ assertEquals(1, attNode.getChildren().size());
+
+ DiffNode refinedDiffNode = (DiffNode)attNode.getChildren().get(0);
+ assertFalse(filter.getPredicateWhenSelected().apply(refinedDiffNode));
+ assertFalse(filter.getPredicateWhenUnselected().apply(refinedDiffNode));
+ assertEquals(1, refinedDiffNode.getChildren().size());
+
+ // It's useless to test on the refining diff since filters are not applied on refining diffs
+ }
+
+ /**
+ * A non-conflicting cascading refined diff is filtered if it has some pseudo but no real conflict diff
+ * among its refining diffs.
+ */
+ @Test
+ public void testWithPseudoConflictRefiningDiffs() {
+ Match rootMatch = comp.getMatches().get(0);
+ Match cMatch = rootMatch.getSubmatches().get(0);
+ Match attMatch = cMatch.getSubmatches().get(0);
+ Diff attAddition = cMatch.getDifferences().get(0);
+
+ createRefinedDiff(attMatch, attAddition);
+
+ createConflict(attAddition, PSEUDO);
+
+ BasicDifferenceGroupImpl group = new BasicDifferenceGroupImpl(comp, Predicates.alwaysTrue(),
+ crossReferenceAdapter);
+ group.buildSubTree();
+ assertEquals(2, group.getChildren().size());
+ MatchNode rootNode = (MatchNode)group.getChildren().get(0);
+ assertTrue(group.getChildren().get(1) instanceof MatchResourceNode);
+
+ assertEquals(1, rootNode.getChildren().size());
+ MatchNode cNode = (MatchNode)rootNode.getChildren().get(0);
+ assertEquals(2, cNode.getChildren().size());
+
+ DiffNode addClassNode = (DiffNode)cNode.getChildren().get(0);
+ assertFalse(filter.getPredicateWhenSelected().apply(addClassNode));
+ assertFalse(filter.getPredicateWhenUnselected().apply(addClassNode));
+
+ MatchNode attNode = (MatchNode)cNode.getChildren().get(1);
+ assertEquals(1, attNode.getChildren().size());
+
+ DiffNode refinedDiffNode = (DiffNode)attNode.getChildren().get(0);
+ assertTrue(filter.getPredicateWhenSelected().apply(refinedDiffNode));
+ assertFalse(filter.getPredicateWhenUnselected().apply(refinedDiffNode));
+ assertEquals(1, refinedDiffNode.getChildren().size());
+
+ // It's useless to test on the refining diff since filters are not applied on refining diffs
+ }
+
+ protected void createConflict(Diff attAddition, ConflictKind kind) {
+ Conflict conflict = CompareFactory.eINSTANCE.createConflict();
+ conflict.setKind(kind);
+ conflict.getDifferences().add(attAddition);
+ comp.getConflicts().add(conflict);
+ }
+
+ protected void createRefinedDiff(Match attMatch, Diff attAddition) {
+ Diff refinedDiff = CompareFactory.eINSTANCE.createDiff();
+ refinedDiff.getRefinedBy().add(attAddition);
+ attMatch.getDifferences().add(refinedDiff);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ comp = getComparison(new CascadingScope());
+ crossReferenceAdapter = new TestECrossReferenceAdapter();
+ filter = new CascadingDifferencesFilter();
+ }
+
+ private class TestECrossReferenceAdapter extends ECrossReferenceAdapter {
+ @Override
+ protected boolean isIncluded(EReference eReference) {
+ return eReference == TreePackage.Literals.TREE_NODE__DATA;
+ }
+ }
+
+ public class CascadingScope extends AbstractInputData implements ResourceScopeProvider {
+
+ public Resource getOrigin() throws IOException {
+ return loadFromClassLoader("data/cascading/ancestor.ecore");//$NON-NLS-1$
+ }
+
+ public Resource getLeft() throws IOException {
+ return loadFromClassLoader("data/cascading/left.ecore");//$NON-NLS-1$
+ }
+
+ public Resource getRight() throws IOException {
+ return loadFromClassLoader("data/cascading/right.ecore");//$NON-NLS-1$
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/TechnicalitiesFilterTests.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/TechnicalitiesFilterTests.java
new file mode 100644
index 000000000..9941219de
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/TechnicalitiesFilterTests.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 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.rcp.ui.tests.structuremergeviewer.filters;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.ide.ui.tests.framework.RuntimeTestRunner;
+import org.eclipse.emf.compare.ide.ui.tests.framework.annotations.Compare;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl.TechnicalitiesFilter;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.ConflictsGroupImpl;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
+import org.eclipse.emf.edit.tree.TreeNode;
+import org.eclipse.emf.edit.tree.TreePackage;
+import org.junit.runner.RunWith;
+
+import com.google.common.base.Predicate;
+
+@SuppressWarnings("restriction")
+@RunWith(RuntimeTestRunner.class)
+public class TechnicalitiesFilterTests {
+
+ /**
+ * This test checks that the following type of pseudo conflicts is filtered by the Technicalities filter.
+ *
+ * <pre>
+ * Ancestor: - root
+ * - class1
+ * - attribute1
+ *
+ * Left: - root
+ *
+ * Right: - root
+ * - class1
+ * </pre>
+ *
+ * @throws IOException
+ */
+ @Compare(left = "data/predicates/technicalities/directPseudoConflict/left.ecore", right = "data/predicates/technicalities/directPseudoConflict/right.ecore", ancestor = "data/predicates/technicalities/directPseudoConflict/ancestor.ecore")
+ public void testDirectPseudoConflictingDiffFilter(Comparison comparison) throws IOException {
+ ConflictsGroupImpl group = new ThreeWayComparisonGroupProvider.ConflictsGroupImpl(comparison,
+ "Conflict", new TestECrossReferenceAdapter());
+ group.buildSubTree();
+ assertEquals(1, group.getChildren().size());
+
+ TreeNode conflictNode = group.getChildren().get(0);
+ assertEquals(1, conflictNode.getChildren().size());
+
+ TreeNode matchNode = conflictNode.getChildren().get(0);
+ assertEquals(2, matchNode.getChildren().size());
+
+ TechnicalitiesFilter filter = new TechnicalitiesFilter();
+ Predicate<? super EObject> selected = filter.getPredicateWhenSelected();
+ Predicate<? super EObject> unselected = filter.getPredicateWhenUnselected();
+
+ TreeNode diffNode1 = matchNode.getChildren().get(0);
+ assertTrue(selected.apply(diffNode1));
+ assertFalse(unselected.apply(diffNode1));
+
+ TreeNode diffNode2 = matchNode.getChildren().get(1);
+ assertTrue(selected.apply(diffNode2));
+ assertFalse(unselected.apply(diffNode2));
+ }
+
+ private class TestECrossReferenceAdapter extends ECrossReferenceAdapter {
+ @Override
+ protected boolean isIncluded(EReference eReference) {
+ return eReference == TreePackage.Literals.TREE_NODE__DATA;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/ancestor.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/ancestor.ecore
new file mode 100644
index 000000000..8dbb83c21
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/ancestor.ecore
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
+ name="root" xmi:id="_root"/>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/left.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/left.ecore
new file mode 100644
index 000000000..70ad02ab5
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/left.ecore
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="root" xmi:id="_root">
+ <eClassifiers xsi:type="ecore:EClass" name="c" xmi:id="_c">
+ <eStructuralFeatures xsi:type="ecore:EAttribute" name="att" xmi:id="_att"/>
+ </eClassifiers>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/right.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/right.ecore
new file mode 100644
index 000000000..8dbb83c21
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/cascading/right.ecore
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
+ name="root" xmi:id="_root"/>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/ancestor.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/ancestor.ecore
new file mode 100644
index 000000000..2d1ac9c5f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/ancestor.ecore
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="root" nsURI="root" nsPrefix="root">
+ <eClassifiers xsi:type="ecore:EClass" name="Class1">
+ <eStructuralFeatures xsi:type="ecore:EAttribute" name="attribute1"/>
+ </eClassifiers>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/left.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/left.ecore
new file mode 100644
index 000000000..96e3d2312
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/left.ecore
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
+ name="root" nsURI="root" nsPrefix="root"/>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/right.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/right.ecore
new file mode 100644
index 000000000..38398404a
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/filters/data/predicates/technicalities/directPseudoConflict/right.ecore
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="root" nsURI="root" nsPrefix="root">
+ <eClassifiers xsi:type="ecore:EClass" name="Class1"/>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupTest.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupTest.java
new file mode 100644
index 000000000..f5cc65a29
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupTest.java
@@ -0,0 +1,625 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo and others.
+ * 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
+ * Tanja Mayerhofer - bug 501864
+ *******************************************************************************/
+package org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups;
+
+import static com.google.common.base.Predicates.and;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.compare.CompareFactory;
+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.rcp.ui.internal.EMFCompareRCPUIMessages;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.StructureMergeViewerFilter;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl.TechnicalitiesFilter;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.BasicDifferenceGroupImpl;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.CompositeConflict;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.ConflictsGroupImpl;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.ConflictNode;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.DiffNode;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.MatchNode;
+import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups.provider.AbstractTestTreeNodeItemProviderAdapter;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
+import org.eclipse.emf.edit.tree.TreeNode;
+import org.eclipse.emf.edit.tree.TreePackage;
+import org.junit.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.eventbus.EventBus;
+
+@SuppressWarnings("restriction")
+public class ConflictsGroupTest extends AbstractTestTreeNodeItemProviderAdapter {
+
+ private static final CompareFactory FACTORY = CompareFactory.eINSTANCE;
+
+ private ECrossReferenceAdapter crossReferenceAdapter;
+
+ @Override
+ public void before() throws IOException {
+ super.before();
+ crossReferenceAdapter = new TestECrossReferenceAdapter();
+ }
+
+ /**
+ * Tests that multiple conflicts containing overlapping diffs are merged in the SMV. Overlapping diffs can
+ * happen due to the replacement of refining diffs with their refined diffs in the SMV. This test is
+ * related to <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ */
+ @Test
+ public void testMergingMultipleConflictsWithOverlappingDiffs() {
+ // Create diffs
+ final Diff diff1 = FACTORY.createDiff();
+ final Diff diff1a = FACTORY.createDiff();
+ final Diff diff1b = FACTORY.createDiff();
+ diff1.getRefinedBy().add(diff1a);
+ diff1.getRefinedBy().add(diff1b);
+
+ final Diff diff2 = FACTORY.createDiff();
+
+ final Diff diff3 = FACTORY.createDiff();
+ final Diff diff3a = FACTORY.createDiff();
+ final Diff diff3b = FACTORY.createDiff();
+ diff3.getRefinedBy().add(diff3a);
+ diff3.getRefinedBy().add(diff3b);
+
+ final Diff diff4 = FACTORY.createDiff();
+
+ // Create overlapping conflicts
+ Conflict conflict1 = FACTORY.createConflict();
+ conflict1.getDifferences().add(diff1a);
+ conflict1.getDifferences().add(diff2);
+
+ Conflict conflict2 = FACTORY.createConflict();
+ conflict2.getDifferences().add(diff3a);
+ conflict2.getDifferences().add(diff4);
+
+ Conflict conflict3 = FACTORY.createConflict();
+ conflict3.getDifferences().add(diff1b);
+ conflict3.getDifferences().add(diff3b);
+
+ // Create comparison
+ final Comparison comparison = FACTORY.createComparison();
+ comparison.getConflicts().add(conflict1);
+ comparison.getConflicts().add(conflict2);
+ comparison.getConflicts().add(conflict3);
+
+ // Build conflict nodes
+ final ConflictsGroupImpl conflictsGroup = buildConflictGroup(comparison);
+
+ // One conflict node was created
+ List<? extends TreeNode> conflictNodes = conflictsGroup.getChildren();
+ assertEquals(1, conflictNodes.size());
+
+ // The conflict node groups the three created conflicts
+ ConflictNode conflictNode = (ConflictNode)conflictNodes.get(0);
+ CompositeConflict compositeConflict = (CompositeConflict)conflictNode.basicGetData();
+ assertEquals(3, compositeConflict.getConflicts().size());
+
+ // The composite conflict contains all refined diffs
+ EList<Diff> differences = compositeConflict.getDifferences();
+ assertEquals(4, differences.size());
+ assertTrue(differences.contains(diff1));
+ assertTrue(differences.contains(diff2));
+ assertTrue(differences.contains(diff3));
+ assertTrue(differences.contains(diff4));
+ }
+
+ /**
+ * Tests that a composite conflict has the conflict kind {@link ConflictKind#REAL} if it contains at least
+ * one conflict of conflict kind {@link ConflictKind#REAL}. This test is related to <a
+ * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ */
+ @Test
+ public void testDerivationOfConflictGroupKindReal() {
+ final Conflict realConflict = FACTORY.createConflict();
+ realConflict.setKind(ConflictKind.REAL);
+
+ final Conflict pseudoConflict = FACTORY.createConflict();
+ pseudoConflict.setKind(ConflictKind.PSEUDO);
+
+ final CompositeConflict realCompositeConflict = new CompositeConflict(realConflict);
+ assertEquals(ConflictKind.REAL, realCompositeConflict.getKind());
+
+ final CompositeConflict pseudoCompositeConflict = new CompositeConflict(pseudoConflict);
+ assertEquals(ConflictKind.PSEUDO, pseudoCompositeConflict.getKind());
+
+ // The union of one real conflict and one pseudo conflict results in a composite conflict with
+ // conflict kind real
+ pseudoCompositeConflict.join(realCompositeConflict);
+ final CompositeConflict mergedConflictGroup = pseudoCompositeConflict;
+ assertEquals(2, mergedConflictGroup.getConflicts().size());
+ assertTrue(mergedConflictGroup.getConflicts().contains(realConflict));
+ assertTrue(mergedConflictGroup.getConflicts().contains(pseudoConflict));
+ assertEquals(ConflictKind.REAL, mergedConflictGroup.getKind());
+ }
+
+ /**
+ * Tests that a composite conflict has the conflict kind {@link ConflictKind#PSEUDO} if it contains only
+ * conflicts of conflict kind {@link ConflictKind#PSEUDO}. This test is related to <a
+ * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ */
+ @Test
+ public void testDerivationOfConflictGroupKindPseudo() {
+ final Conflict pseudoConflict1 = FACTORY.createConflict();
+ pseudoConflict1.setKind(ConflictKind.PSEUDO);
+
+ final Conflict pseudoConflict2 = FACTORY.createConflict();
+ pseudoConflict2.setKind(ConflictKind.PSEUDO);
+
+ final CompositeConflict pseudoCompositeConflict1 = new CompositeConflict(pseudoConflict1);
+ assertEquals(ConflictKind.PSEUDO, pseudoCompositeConflict1.getKind());
+
+ final CompositeConflict pseudoCompositeConflict2 = new CompositeConflict(pseudoConflict2);
+ assertEquals(ConflictKind.PSEUDO, pseudoCompositeConflict2.getKind());
+
+ // The union of pseudo conflicts results in a composite conflict with conflict kind pseudo
+ pseudoCompositeConflict2.join(pseudoCompositeConflict1);
+ final CompositeConflict mergedConflictGroup = pseudoCompositeConflict2;
+ assertEquals(2, mergedConflictGroup.getConflicts().size());
+ assertTrue(mergedConflictGroup.getConflicts().contains(pseudoConflict1));
+ assertTrue(mergedConflictGroup.getConflicts().contains(pseudoConflict2));
+ assertEquals(ConflictKind.PSEUDO, mergedConflictGroup.getKind());
+ }
+
+ /**
+ * Tests that a refined diff whose refinding diffs are involved in a real conflict
+ * {@link ConflictKind#REAL} is only shown in the conflicts group but not in the left or right diff group.
+ * This test is related to <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ */
+ @Test
+ public void testRefinedDiffsWithRealConflictsAreOnlyInConflictGroup() {
+ ConflictsGroupWithRefinedDiffTestScenario scenario = new ConflictsGroupWithRefinedDiffTestScenario();
+
+ // Create real conflict between refining diffs
+ final Conflict conflict = scenario.addConflict(scenario.diff1b, scenario.diff2b, ConflictKind.REAL);
+
+ // Build conflict nodes
+ final ConflictsGroupImpl conflictsGroup = buildConflictGroup(scenario.comparison);
+
+ // One conflict node was created
+ final List<? extends TreeNode> conflictNodes = conflictsGroup.getChildren();
+ assertEquals(1, conflictNodes.size());
+
+ // The conflict node is associated with the created conflict
+ final ConflictNode conflictNode = (ConflictNode)conflictNodes.get(0);
+ final CompositeConflict conflictNodeConflict = (CompositeConflict)conflictNode.basicGetData();
+ assertEquals(1, conflictNodeConflict.getConflicts().size());
+ assertTrue(conflictNodeConflict.getConflicts().contains(conflict));
+
+ // The conflict node contains diff nodes for the refined diffs
+ assertEquals(1, conflictNode.getChildren().size());
+ final MatchNode matchNode = (MatchNode)conflictNode.getChildren().get(0);
+ assertTrue(matchNodeContainsDiffNodesForDiffs(matchNode, scenario.diff1, scenario.diff2));
+
+ // The technicalities filter does not filter this conflict, because there is a real conflict between
+ // the refining diffs
+ final List<? extends TreeNode> conflictDiffNodesFiltered = applyTechnicalitiesFilter(
+ matchNode.getChildren());
+ assertEquals(2, conflictDiffNodesFiltered.size());
+
+ // Build left side
+ final BasicDifferenceGroupImpl leftSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.LEFT);
+
+ // There are no diffs in the left side
+ assertEquals(0, leftSide.getChildren().size());
+
+ // Build right side
+ final BasicDifferenceGroupImpl rightSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.RIGHT);
+
+ // There are no diffs in the right side
+ assertEquals(0, rightSide.getChildren().size());
+ }
+
+ /**
+ * Tests that a refined diff whose refining diffs are involved in a real conflict
+ * {@link ConflictKind#REAL} and in a pseudo conflict {@link ConflictKind#REAL} is only shown in the
+ * conflicts group but not in the left or right diff group. This test is related to <a
+ * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ */
+ @Test
+ public void testRefinedDiffsWithRealAndPseudoConflictsAreOnlyInConflictGroup() {
+ ConflictsGroupWithRefinedDiffTestScenario scenario = new ConflictsGroupWithRefinedDiffTestScenario();
+
+ // Create real conflict between refining diffs
+ final Conflict conflictReal = scenario.addConflict(scenario.diff1b, scenario.diff2b,
+ ConflictKind.REAL);
+
+ // Create pseudo conflict between refining diffs
+ final Conflict conflictPseudo = scenario.addConflict(scenario.diff1a, scenario.diff2a,
+ ConflictKind.PSEUDO);
+
+ // Build conflict nodes
+ final ConflictsGroupImpl conflictsGroup = buildConflictGroup(scenario.comparison);
+
+ // One conflict node was created
+ final List<? extends TreeNode> conflictNodes = conflictsGroup.getChildren();
+ assertEquals(1, conflictNodes.size());
+
+ // The conflict node is associated with the created conflicts
+ final ConflictNode conflictNode = (ConflictNode)conflictNodes.get(0);
+ final CompositeConflict conflictNodeConflict = (CompositeConflict)conflictNode.basicGetData();
+ assertEquals(2, conflictNodeConflict.getConflicts().size());
+ assertTrue(conflictNodeConflict.getConflicts().contains(conflictReal));
+ assertTrue(conflictNodeConflict.getConflicts().contains(conflictPseudo));
+
+ // The conflict node contains diff nodes for the refined diffs
+ assertEquals(1, conflictNode.getChildren().size());
+ final MatchNode matchNode = (MatchNode)conflictNode.getChildren().get(0);
+ assertTrue(matchNodeContainsDiffNodesForDiffs(matchNode, scenario.diff1, scenario.diff2));
+
+ // The technicalities filter does not filter this conflict, because there is a real conflict between
+ // the refining diffs
+ final List<? extends TreeNode> conflictDiffNodesFiltered = applyTechnicalitiesFilter(
+ matchNode.getChildren());
+ assertEquals(2, conflictDiffNodesFiltered.size());
+
+ // Build left side
+ final BasicDifferenceGroupImpl leftSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.LEFT);
+
+ // There are no diffs in the left side
+ assertEquals(0, leftSide.getChildren().size());
+
+ // Build right side
+ final BasicDifferenceGroupImpl rightSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.RIGHT);
+
+ // There are no diffs in the right side
+ assertEquals(0, rightSide.getChildren().size());
+ }
+
+ /**
+ * Tests that a refined diff that is refined by diffs who are all involved in pseudo conflicts
+ * {@link ConflictKind#REAL} is only shown in the conflicts group but not in the left or right diff group.
+ * This test is related to <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ */
+ @Test
+ public void testRefinedDiffsWithOnlyPseudoConflictsAreOnlyInConflictGroup() {
+ ConflictsGroupWithRefinedDiffTestScenario scenario = new ConflictsGroupWithRefinedDiffTestScenario();
+
+ // Create pseudo conflicts between refining diffs
+ final Conflict conflictPseudo1 = scenario.addConflict(scenario.diff1b, scenario.diff2b,
+ ConflictKind.PSEUDO);
+ final Conflict conflictPseudo2 = scenario.addConflict(scenario.diff1a, scenario.diff2a,
+ ConflictKind.PSEUDO);
+
+ // Build conflict nodes
+ final ConflictsGroupImpl conflictsGroup = buildConflictGroup(scenario.comparison);
+
+ // One conflict node was created
+ final List<? extends TreeNode> conflictNodes = conflictsGroup.getChildren();
+ assertEquals(1, conflictNodes.size());
+
+ // The conflict node is associated with the created conflicts
+ final ConflictNode conflictNode = (ConflictNode)conflictNodes.get(0);
+ final CompositeConflict conflictNodeConflict = (CompositeConflict)conflictNode.basicGetData();
+ assertEquals(2, conflictNodeConflict.getConflicts().size());
+ assertTrue(conflictNodeConflict.getConflicts().contains(conflictPseudo1));
+ assertTrue(conflictNodeConflict.getConflicts().contains(conflictPseudo2));
+
+ // The conflict node contains diff nodes for the refined diffs
+ assertEquals(1, conflictNode.getChildren().size());
+ final MatchNode matchNode = (MatchNode)conflictNode.getChildren().get(0);
+ assertTrue(matchNodeContainsDiffNodesForDiffs(matchNode, scenario.diff1, scenario.diff2));
+
+ // The technicalities filter filters this conflict, since the involved refined diffs are refined by
+ // diffs that are all involved in pseudo conflicts
+ final List<? extends TreeNode> conflictDiffNodesFiltered = applyTechnicalitiesFilter(
+ matchNode.getChildren());
+ assertEquals(0, conflictDiffNodesFiltered.size());
+
+ // Build left side
+ final BasicDifferenceGroupImpl leftSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.LEFT);
+
+ // There are no diffs in the left side
+ assertEquals(0, leftSide.getChildren().size());
+
+ // Build right side
+ final BasicDifferenceGroupImpl rightSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.RIGHT);
+
+ // There are no diffs in the right side
+ assertEquals(0, rightSide.getChildren().size());
+ }
+
+ /**
+ * Tests that a refined diff that is refined by one diff involved in a pseudo conflict
+ * {@link ConflictKind#PSEUDO} and one diff involved in no conflict is shown only in the side group. This
+ * test is related to <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ */
+ @Test
+ public void testRefinedDiffsWithOnlyOnePseudoConflictAreInDiffGroupOnly() {
+ ConflictsGroupWithRefinedDiffTestScenario scenario = new ConflictsGroupWithRefinedDiffTestScenario();
+
+ // Create pseudo conflict
+ final Conflict conflictPseudo = scenario.addConflict(scenario.diff1b, scenario.diff2b,
+ ConflictKind.PSEUDO);
+
+ // Build conflict nodes
+ final ConflictsGroupImpl conflictsGroup = buildConflictGroup(scenario.comparison);
+
+ // One conflict node was created
+ List<? extends TreeNode> conflictNodes = conflictsGroup.getChildren();
+ assertEquals(1, conflictNodes.size());
+
+ // The conflict node is associated with the created conflict
+ ConflictNode conflictNode = (ConflictNode)conflictNodes.get(0);
+ CompositeConflict conflictNodeConflict = (CompositeConflict)conflictNode.basicGetData();
+ assertEquals(1, conflictNodeConflict.getConflicts().size());
+ assertTrue(conflictNodeConflict.getConflicts().contains(conflictPseudo));
+
+ // The conflict node contains diff nodes for the refined diffs
+ assertEquals(1, conflictNode.getChildren().size());
+ MatchNode matchNode = (MatchNode)conflictNode.getChildren().get(0);
+ assertTrue(matchNodeContainsDiffNodesForDiffs(matchNode, scenario.diff1, scenario.diff2));
+
+ // The technicalities filter does not filter this conflict, because it involved a refined diff that is
+ // refined by a diff that is not involved in a conflict
+ final List<? extends TreeNode> conflictDiffNodesFiltered = applyTechnicalitiesFilter(
+ matchNode.getChildren());
+ assertEquals(2, conflictDiffNodesFiltered.size());
+
+ // Build left side
+ final BasicDifferenceGroupImpl leftSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.LEFT);
+
+ // There is one refined diff in the left side, which is refined by one diff that is not in a conflict
+ // and one diff that is in a PSEUDO conflict
+ assertEquals(1, leftSide.getChildren().size());
+ MatchNode matchNodeLeft = (MatchNode)leftSide.getChildren().get(0);
+ assertTrue(matchNodeContainsDiffNodesForDiffs(matchNodeLeft, scenario.diff1));
+
+ // The technicalities filter does not filter the changes on the left side, because the refined diff is
+ // refined by a diff that is not involved in a conflict
+ final List<? extends TreeNode> diffNodesLeftFiltered = applyTechnicalitiesFilter(
+ matchNodeLeft.getChildren());
+ assertEquals(1, diffNodesLeftFiltered.size());
+ final List<? extends TreeNode> subDiffNodesLeftFiltered = applyTechnicalitiesFilter(
+ diffNodesLeftFiltered.get(0).getChildren());
+ assertEquals(1, subDiffNodesLeftFiltered.size());
+
+ // Build right side
+ final BasicDifferenceGroupImpl rightSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.RIGHT);
+
+ // There is one refined diff in the right side, which is refined by one diff that is not in a conflict
+ // and one diff that is in a PSEUDO conflict
+ assertEquals(1, rightSide.getChildren().size());
+ MatchNode matchNodeRight = (MatchNode)rightSide.getChildren().get(0);
+ assertTrue(matchNodeContainsDiffNodesForDiffs(matchNodeRight, scenario.diff2));
+
+ // The technicalities filter does not filter the changes on the right side, because the refined diff
+ // is refined by a diff that is not involved in a conflict
+ final List<? extends TreeNode> diffNodesRightFiltered = applyTechnicalitiesFilter(
+ matchNodeRight.getChildren());
+ assertEquals(1, diffNodesRightFiltered.size());
+ final List<? extends TreeNode> subDiffNodesRightFiltered = applyTechnicalitiesFilter(
+ diffNodesRightFiltered.get(0).getChildren());
+ assertEquals(1, subDiffNodesRightFiltered.size());
+ }
+
+ /**
+ * Tests that a refined diff that is directly involved in a pseudo conflict {@link ConflictKind#PSEUDO}
+ * and that is refined by one diff involved in a real conflict {@link ConflictKind#REAL} is shown in the
+ * conflicts group. This test is related to <a
+ * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ */
+ @Test
+ public void testRefinedDiffsInPseudoConflictAndWithRefiningDiffsInRealConflictAreInConflictGroup() {
+ ConflictsGroupWithRefinedDiffTestScenario scenario = new ConflictsGroupWithRefinedDiffTestScenario();
+
+ // Create pseudo conflict
+ final Conflict conflictPseudo = scenario.addConflict(scenario.diff1, scenario.diff2,
+ ConflictKind.PSEUDO);
+
+ // Create real conflict
+ final Conflict conflictReal = scenario.addConflict(scenario.diff1b, scenario.diff2b,
+ ConflictKind.REAL);
+
+ // Build conflict nodes
+ final ConflictsGroupImpl conflictsGroup = buildConflictGroup(scenario.comparison);
+
+ // One conflict node was created
+ List<? extends TreeNode> conflictNodes = conflictsGroup.getChildren();
+ assertEquals(1, conflictNodes.size());
+
+ // The conflict node is associated with both created conflicts
+ ConflictNode conflictNode = (ConflictNode)conflictNodes.get(0);
+ CompositeConflict conflictNodeConflict = (CompositeConflict)conflictNode.basicGetData();
+ assertEquals(2, conflictNodeConflict.getConflicts().size());
+ assertTrue(conflictNodeConflict.getConflicts().contains(conflictPseudo));
+ assertTrue(conflictNodeConflict.getConflicts().contains(conflictReal));
+
+ // The conflict node contains diff nodes for the refined diffs
+ assertEquals(1, conflictNode.getChildren().size());
+ MatchNode matchNode = (MatchNode)conflictNode.getChildren().get(0);
+ assertTrue(matchNodeContainsDiffNodesForDiffs(matchNode, scenario.diff1, scenario.diff2));
+
+ // The technicalities filter does not filter this conflict, because there is a real conflict between
+ // the refining diffs
+ final List<? extends TreeNode> conflictDiffNodesFiltered = applyTechnicalitiesFilter(
+ matchNode.getChildren());
+ assertEquals(2, conflictDiffNodesFiltered.size());
+
+ // Build left side
+ final BasicDifferenceGroupImpl leftSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.LEFT);
+
+ // There are no diffs in the left side
+ assertEquals(0, leftSide.getChildren().size());
+
+ // Build right side
+ final BasicDifferenceGroupImpl rightSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.RIGHT);
+
+ // There are no diffs in the right side
+ assertEquals(0, rightSide.getChildren().size());
+ }
+
+ /**
+ * Tests that a refined diff that is neither directly nor indirect involved in any conflict is shown in
+ * the left or right diff group. This test is related to <a
+ * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ */
+ @Test
+ public void testRefinedDiffsWithoutConfictsAreInDiffGroup() {
+ ConflictsGroupWithRefinedDiffTestScenario scenario = new ConflictsGroupWithRefinedDiffTestScenario();
+
+ // Build conflict nodes
+ final ConflictsGroupImpl conflictsGroup = buildConflictGroup(scenario.comparison);
+
+ // No conflict node was created
+ assertEquals(0, conflictsGroup.getChildren().size());
+
+ // Build left side
+ final BasicDifferenceGroupImpl leftSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.LEFT);
+
+ // There is one refined diff in the left side, which is neither directly nor indirectly involved in a
+ // conflict
+ assertEquals(1, leftSide.getChildren().size());
+ MatchNode matchNodeLeft = (MatchNode)leftSide.getChildren().get(0);
+ assertTrue(matchNodeContainsDiffNodesForDiffs(matchNodeLeft, scenario.diff1));
+
+ // The technicalities filter does not filter the changes on the left side, because they are not
+ // involved in conflicts
+ final List<? extends TreeNode> diffNodesLeftFiltered = applyTechnicalitiesFilter(
+ matchNodeLeft.getChildren());
+ assertEquals(1, diffNodesLeftFiltered.size());
+ final List<? extends TreeNode> subDiffNodesLeftFiltered = applyTechnicalitiesFilter(
+ diffNodesLeftFiltered.get(0).getChildren());
+ assertEquals(2, subDiffNodesLeftFiltered.size());
+
+ // Build right side
+ final BasicDifferenceGroupImpl rightSide = buildDifferenceGroup(scenario.comparison,
+ DifferenceSource.RIGHT);
+
+ // There is one refined diff in the right side, which is neither directly nor indirectly involved in a
+ // conflict
+ assertEquals(1, rightSide.getChildren().size());
+ MatchNode matchNodeRight = (MatchNode)rightSide.getChildren().get(0);
+ assertTrue(matchNodeContainsDiffNodesForDiffs(matchNodeRight, scenario.diff2));
+
+ // The technicalities filter does not filter the changes on the right side, because they are not
+ // involved in conflicts
+ final List<? extends TreeNode> diffNodesRightFiltered = applyTechnicalitiesFilter(
+ matchNodeRight.getChildren());
+ assertEquals(1, diffNodesRightFiltered.size());
+ final List<? extends TreeNode> subDiffNodesRightFiltered = applyTechnicalitiesFilter(
+ diffNodesRightFiltered.get(0).getChildren());
+ assertEquals(2, subDiffNodesRightFiltered.size());
+
+ }
+
+ private class TestECrossReferenceAdapter extends ECrossReferenceAdapter {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.ecore.util.ECrossReferenceAdapter#isIncluded(org.eclipse.emf.ecore.EReference)
+ */
+ @Override
+ protected boolean isIncluded(EReference eReference) {
+ return eReference == TreePackage.Literals.TREE_NODE__DATA;
+ }
+ }
+
+ private ConflictsGroupImpl buildConflictGroup(Comparison comparison) {
+ final ConflictsGroupImpl conflictsGroup = new ConflictsGroupImpl(comparison,
+ EMFCompareRCPUIMessages.getString("ThreeWayComparisonGroupProvider.conflicts.label"), //$NON-NLS-1$
+ crossReferenceAdapter);
+ conflictsGroup.buildSubTree();
+ return conflictsGroup;
+ }
+
+ private BasicDifferenceGroupImpl buildDifferenceGroup(Comparison comparison, DifferenceSource source) {
+ final BasicDifferenceGroupImpl differenceGroup = new BasicDifferenceGroupImpl(comparison,
+ and(fromSide(source), ThreeWayComparisonGroupProvider.DEFAULT_DIFF_GROUP_FILTER_PREDICATE),
+ "", crossReferenceAdapter);
+ differenceGroup.buildSubTree();
+ return differenceGroup;
+ }
+
+ private boolean matchNodeContainsDiffNodesForDiffs(MatchNode matchNode, Diff... diffs) {
+ final boolean matchNodeContainsRightAmountOfChildren = matchNode.getChildren().size() == diffs.length;
+ boolean matchNodeContainsDiffNodesForDiffs = true;
+ for (Diff diff : diffs) {
+ DiffNode diffNode = getDiffNode(matchNode.getChildren(), diff);
+ if (!isDiffNodeForDiff(diffNode, diff)) {
+ matchNodeContainsDiffNodesForDiffs = false;
+ }
+ }
+ return matchNodeContainsRightAmountOfChildren && matchNodeContainsDiffNodesForDiffs;
+ }
+
+ private DiffNode getDiffNode(EList<TreeNode> nodes, Diff diff) {
+ for (TreeNode node : nodes) {
+ if (node instanceof DiffNode) {
+ DiffNode diffNode = (DiffNode)node;
+ if (diffNode.basicGetData() == diff) {
+ return diffNode;
+ }
+ }
+ }
+ return null;
+ }
+
+ private boolean isDiffNodeForDiff(DiffNode diffNode, Diff diff) {
+ if (diffNode == null || diff == null) {
+ return false;
+ }
+ final boolean diffNodeAssociatedWithDiff = diffNode.basicGetData() == diff;
+ final boolean diffNodeContainsRightAmountOfChildren = diffNode.getChildren().size() == diff
+ .getRefinedBy().size();
+ boolean diffNodeContainsNodesForRefiningDiffs = true;
+ for (Diff refiningDiff : diff.getRefinedBy()) {
+ final DiffNode diffNodeForRefiningDiff = getDiffNode(diffNode.getChildren(), refiningDiff);
+ if (diffNodeForRefiningDiff == null) {
+ diffNodeContainsNodesForRefiningDiffs = false;
+ }
+ }
+ return diffNodeAssociatedWithDiff && diffNodeContainsRightAmountOfChildren
+ && diffNodeContainsNodesForRefiningDiffs;
+ }
+
+ private List<? extends TreeNode> applyTechnicalitiesFilter(List<? extends TreeNode> actualTrees) {
+ final StructureMergeViewerFilter filter = new StructureMergeViewerFilter(new EventBus());
+ final TechnicalitiesFilter technicalitiesFilter = new TechnicalitiesFilter();
+ filter.addFilter(technicalitiesFilter);
+ Predicate<EObject> viewerFilterPredicate = new Predicate<EObject>() {
+ public boolean apply(EObject input) {
+ AdapterImpl adapter = new AdapterImpl();
+ adapter.setTarget(input);
+ return filter.select(null, null, adapter);
+ }
+ };
+ List<? extends TreeNode> filteredTrees = Lists
+ .newArrayList(Collections2.filter(actualTrees, viewerFilterPredicate));
+ return filteredTrees;
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupWithRefinedDiffTestScenario.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupWithRefinedDiffTestScenario.java
new file mode 100644
index 000000000..95f973a3c
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/ConflictsGroupWithRefinedDiffTestScenario.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Services GmbH and others.
+ * 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:
+ * Tanja Mayerhofer - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups;
+
+import org.eclipse.emf.compare.CompareFactory;
+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;
+
+/**
+ * This test scenario creates a comparison like this:
+ * <ul>
+ * <li>diff1 (LEFT), refined by
+ * <ul>
+ * <li>diff1a (LEFT)</li>
+ * <li>diff1b (RIGHT)</li>
+ * </ul>
+ * </li>
+ * <li>diff2 (RIGHT), refined by
+ * <ul>
+ * <li>diff2a (LEFT)</li>
+ * <li>diff2b (RIGHT)</li>
+ * </ul>
+ * </li>
+ * </ul>
+ */
+public class ConflictsGroupWithRefinedDiffTestScenario {
+
+ private static final CompareFactory FACTORY = CompareFactory.eINSTANCE;
+
+ final Diff diff1;
+
+ final Diff diff1a;
+
+ final Diff diff1b;
+
+ final Diff diff2;
+
+ final Diff diff2a;
+
+ final Diff diff2b;
+
+ final Comparison comparison;
+
+ public ConflictsGroupWithRefinedDiffTestScenario() {
+ // Create diffs left side
+ diff1 = FACTORY.createDiff();
+ diff1a = FACTORY.createDiff();
+ diff1b = FACTORY.createDiff();
+ diff1.getRefinedBy().add(diff1a);
+ diff1.getRefinedBy().add(diff1b);
+
+ diff1.setSource(DifferenceSource.LEFT);
+ diff1a.setSource(DifferenceSource.LEFT);
+ diff1b.setSource(DifferenceSource.LEFT);
+
+ // Create diffs right side
+ diff2 = FACTORY.createDiff();
+ diff2a = FACTORY.createDiff();
+ diff2b = FACTORY.createDiff();
+ diff2.getRefinedBy().add(diff2a);
+ diff2.getRefinedBy().add(diff2b);
+
+ diff2.setSource(DifferenceSource.RIGHT);
+ diff2a.setSource(DifferenceSource.RIGHT);
+ diff2b.setSource(DifferenceSource.RIGHT);
+
+ // Create comparison
+ comparison = FACTORY.createComparison();
+ comparison.setThreeWay(true);
+ final Match match1 = FACTORY.createMatch();
+ match1.getDifferences().add(diff1);
+ match1.getDifferences().add(diff1a);
+ match1.getDifferences().add(diff1b);
+ match1.getDifferences().add(diff2);
+ match1.getDifferences().add(diff2a);
+ match1.getDifferences().add(diff2b);
+ comparison.getMatches().add(match1);
+ }
+
+ /**
+ * Add a conflict between 2 existing differences of this scenario's comparison.
+ *
+ * @param conflictingDiff1
+ * @param conflictingDiff2
+ * @param kind
+ * @return The created conflict.
+ */
+ Conflict addConflict(Diff conflictingDiff1, Diff conflictingDiff2, ConflictKind kind) {
+ final Conflict conflict = FACTORY.createConflict();
+ conflict.getDifferences().add(conflictingDiff1);
+ conflict.getDifferences().add(conflictingDiff2);
+ conflict.setKind(kind);
+ comparison.getConflicts().add(conflict);
+ return conflict;
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/AbstractTestTreeNodeItemProviderAdapter.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/AbstractTestTreeNodeItemProviderAdapter.java
index 42fcbe9a4..b204c8e0e 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/AbstractTestTreeNodeItemProviderAdapter.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/AbstractTestTreeNodeItemProviderAdapter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2015 Obeo.
+ * 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
@@ -20,9 +20,9 @@ import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.compare.AttributeChange;
import org.eclipse.emf.compare.Comparison;
import org.eclipse.emf.compare.EMFCompare;
+import org.eclipse.emf.compare.EMFCompare.Builder;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.ReferenceChange;
-import org.eclipse.emf.compare.EMFCompare.Builder;
import org.eclipse.emf.compare.rcp.internal.extension.impl.EMFCompareBuilderConfigurator;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.StructureMergeViewerFilter;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.provider.TreeItemProviderAdapterFactorySpec;
@@ -46,7 +46,7 @@ import com.google.common.eventbus.EventBus;
@SuppressWarnings("restriction")
public class AbstractTestTreeNodeItemProviderAdapter {
- protected static TreeItemProviderAdapterFactorySpec treeItemProviderAdapterFactory;
+ protected TreeItemProviderAdapterFactorySpec treeItemProviderAdapterFactory;
protected EventBus eventBus;
@@ -61,7 +61,7 @@ public class AbstractTestTreeNodeItemProviderAdapter {
* @return the comparison
* @throws IOException
*/
- protected static Comparison getComparison(ResourceScopeProvider scopeProvider) throws IOException {
+ public static Comparison getComparison(ResourceScopeProvider scopeProvider) throws IOException {
final IComparisonScope scope = new DefaultComparisonScope(scopeProvider.getLeft(),
scopeProvider.getRight(), scopeProvider.getOrigin());
final Builder builder = EMFCompare.builder();
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/MatchOfContainmentReferenceChangeAdapterTest.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/MatchOfContainmentReferenceChangeAdapterTest.java
new file mode 100644
index 000000000..d565df9dc
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/MatchOfContainmentReferenceChangeAdapterTest.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 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.rcp.ui.tests.structuremergeviewer.match;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.EMFCompare;
+import org.eclipse.emf.compare.EMFCompare.Builder;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.match.MatchOfContainmentReferenceChangeAdapter;
+import org.eclipse.emf.compare.rcp.internal.extension.impl.EMFCompareBuilderConfigurator;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.match.MatchOfContainmentReferenceChangeProcessor;
+import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.match.data.MatchOfContainmentReferenceChangeAdapterTestData;
+import org.eclipse.emf.compare.scope.DefaultComparisonScope;
+import org.eclipse.emf.compare.scope.IComparisonScope;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.junit.Test;
+
+/**
+ * Tests for {@link MatchOfContainmentReferenceChangeAdapter}.
+ *
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+@SuppressWarnings("restriction")
+public class MatchOfContainmentReferenceChangeAdapterTest {
+
+ private static MatchOfContainmentReferenceChangeAdapterTestData inputData = new MatchOfContainmentReferenceChangeAdapterTestData();
+
+ @Test
+ public void test2wayAddNewStringTypedEReference() throws IOException {
+ final Resource leftResource = inputData.getLeft();
+ final Resource rightResource = inputData.getRight();
+ final IComparisonScope scope = new DefaultComparisonScope(leftResource, rightResource, null);
+ final Builder comparisonBuilder = EMFCompare.builder();
+ EMFCompareBuilderConfigurator.createDefault().configure(comparisonBuilder);
+ final Comparison comparison = comparisonBuilder.build().compare(scope);
+
+ new MatchOfContainmentReferenceChangeProcessor().execute(comparison);
+
+ for (Match match : comparison.getMatches()) {
+ Adapter adapter = EcoreUtil.getAdapter(match.eAdapters(),
+ MatchOfContainmentReferenceChangeAdapter.class);
+ assertNull(adapter);
+ for (Match subMatch : match.getAllSubmatches()) {
+ adapter = EcoreUtil.getAdapter(subMatch.eAdapters(),
+ MatchOfContainmentReferenceChangeAdapter.class);
+ // The only match with a MatchOfContainmentReferenceChangeAdapter is the match on title
+ EObject left = subMatch.getLeft();
+ if (left instanceof EStructuralFeature
+ && ((EStructuralFeature)left).getName().equals("title")) {
+ assertNotNull(adapter);
+ } else {
+ assertNull(adapter);
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/MatchOfContainmentReferenceChangeAdapterTestData.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/MatchOfContainmentReferenceChangeAdapterTestData.java
new file mode 100644
index 000000000..36d89d966
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/MatchOfContainmentReferenceChangeAdapterTestData.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 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.rcp.ui.tests.structuremergeviewer.match.data;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.tests.edit.data.ResourceScopeProvider;
+import org.eclipse.emf.compare.tests.framework.AbstractInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+
+public class MatchOfContainmentReferenceChangeAdapterTestData extends AbstractInputData implements ResourceScopeProvider {
+
+ public Resource getLeft() throws IOException {
+ return loadFromClassLoader("left.ecore");
+ }
+
+ public Resource getRight() throws IOException {
+ return loadFromClassLoader("right.ecore");
+ }
+
+ public Resource getOrigin() throws IOException {
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/left.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/left.ecore
new file mode 100644
index 000000000..f106458be
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/left.ecore
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmi:id="_14sTEG60EeGkd4g88tZXfA" name="extlibrary" nsURI="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0"
+ nsPrefix="extlib">
+ <eClassifiers xsi:type="ecore:EClass" xmi:id="_146VgG60EeGkd4g88tZXfA" name="Book">
+ <eStructuralFeatures xsi:type="ecore:EAttribute" xmi:id="_146VgW60EeGkd4g88tZXfA"
+ name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+ </eClassifiers>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/right.ecore b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/right.ecore
new file mode 100644
index 000000000..82573635c
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/match/data/right.ecore
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmi:id="_14sTEG60EeGkd4g88tZXfA" name="extlibrary" nsURI="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0"
+ nsPrefix="extlib">
+ <eClassifiers xsi:type="ecore:EClass" xmi:id="_146VgG60EeGkd4g88tZXfA" name="Book"/>
+</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/suite/AllTests.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/suite/AllTests.java
index 4447864a0..65a6da209 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/suite/AllTests.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/suite/AllTests.java
@@ -8,24 +8,25 @@
* Contributors:
* Obeo - initial API and implementation
* Philip Langer - bug 486923
+ * Tanja Mayerhofer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.rcp.ui.tests.suite;
-import junit.framework.JUnit4TestAdapter;
-import junit.framework.Test;
-import junit.textui.TestRunner;
-
import org.eclipse.emf.compare.ComparePackage;
+import org.eclipse.emf.compare.rcp.ui.tests.contentmergeviewer.accessor.match.MatchAccessorTest;
import org.eclipse.emf.compare.rcp.ui.tests.match.RCPMatchEngineFactoryRegistryTest;
import org.eclipse.emf.compare.rcp.ui.tests.mergeviewer.item.MergeViewerItemFeatureMapsTest;
import org.eclipse.emf.compare.rcp.ui.tests.mergeviewer.item.MergeViewerItemPseudoConflictTest;
import org.eclipse.emf.compare.rcp.ui.tests.mergeviewer.item.MergeViewerItemTest;
+import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.filters.TechnicalitiesFilterTests;
import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.filters.TestFeatureMapDifferencesFilter;
+import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups.ConflictsGroupTest;
import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups.TestBasicDifferenceGroupImpl;
import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups.provider.TestComparisonTreeNodeItemProviderSpec;
import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups.provider.TestMatchTreeNodeItemProviderSpec;
import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups.provider.TestReferenceChangeTreeNodeItemProviderSpec;
import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups.provider.ThreeWayComparisonGroupProviderTest;
+import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.match.MatchOfContainmentReferenceChangeAdapterTest;
import org.eclipse.emf.compare.tests.nodes.NodesPackage;
import org.eclipse.emf.compare.tests.nodes.util.NodesResourceFactoryImpl;
import org.eclipse.emf.ecore.EPackage;
@@ -35,12 +36,18 @@ import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.textui.TestRunner;
+
@RunWith(Suite.class)
@SuiteClasses({TestComparisonTreeNodeItemProviderSpec.class, TestMatchTreeNodeItemProviderSpec.class,
TestReferenceChangeTreeNodeItemProviderSpec.class, MergeViewerItemTest.class,
MergeViewerItemPseudoConflictTest.class, MergeViewerItemFeatureMapsTest.class,
TestBasicDifferenceGroupImpl.class, BugsTestSuite.class, TestFeatureMapDifferencesFilter.class,
- RCPMatchEngineFactoryRegistryTest.class, ThreeWayComparisonGroupProviderTest.class, })
+ RCPMatchEngineFactoryRegistryTest.class, ThreeWayComparisonGroupProviderTest.class,
+ ConflictsGroupTest.class, MatchAccessorTest.class, TechnicalitiesFilterTests.class,
+ MatchOfContainmentReferenceChangeAdapterTest.class })
public class AllTests {
/**
* Launches the test with the given arguments.
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.compare.rcp.ui/META-INF/MANIFEST.MF
index 432829606..7bb595a2e 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/META-INF/MANIFEST.MF
@@ -46,6 +46,7 @@ Export-Package: org.eclipse.emf.compare.rcp.ui,
org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.extender;x-friends:="org.eclipse.emf.compare.ide.ui",
org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl;x-friends:="org.eclipse.emf.compare.ide.ui,org.eclipse.emf.compare.diagram.papyrus.tests,org.eclipse.emf.compare.uml2.rcp.ui.tests",
org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.provider;x-friends:="org.eclipse.emf.compare.ide.ui,org.eclipse.emf.compare.diagram.papyrus.tests,org.eclipse.emf.compare.uml2.rcp.ui.tests",
+ org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.match,
org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes,
org.eclipse.emf.compare.rcp.ui.internal.util;x-friends:="org.eclipse.emf.compare.ide.ui",
org.eclipse.emf.compare.rcp.ui.mergeviewer,
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/factory/impl/MatchAccessorFactory.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/factory/impl/MatchAccessorFactory.java
index 5110d05d4..562a1b337 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/factory/impl/MatchAccessorFactory.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/factory/impl/MatchAccessorFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2014 Obeo.
+ * Copyright (c) 2012, 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
@@ -11,10 +11,13 @@
package org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.accessor.factory.impl;
import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.legacy.ITypedElement;
import org.eclipse.emf.compare.rcp.ui.internal.contentmergeviewer.accessor.impl.MatchAccessor;
import org.eclipse.emf.compare.rcp.ui.mergeviewer.IMergeViewer.MergeViewerSide;
+import org.eclipse.emf.compare.utils.MatchUtil;
+import org.eclipse.emf.ecore.EObject;
/**
* A specific {@link org.eclipse.emf.compare.rcp.ui.contentmergeviewer.accessor.factory.IAccessorFactory} for
@@ -41,7 +44,8 @@ public class MatchAccessorFactory extends AbstractAccessorFactory {
* java.lang.Object)
*/
public ITypedElement createLeft(AdapterFactory adapterFactory, Object target) {
- return new MatchAccessor(adapterFactory, (Match)target, MergeViewerSide.LEFT);
+ return new MatchAccessor(adapterFactory, (Match)target, getContainmentReferenceChange((Match)target),
+ MergeViewerSide.LEFT);
}
/**
@@ -51,7 +55,8 @@ public class MatchAccessorFactory extends AbstractAccessorFactory {
* java.lang.Object)
*/
public ITypedElement createRight(AdapterFactory adapterFactory, Object target) {
- return new MatchAccessor(adapterFactory, (Match)target, MergeViewerSide.RIGHT);
+ return new MatchAccessor(adapterFactory, (Match)target, getContainmentReferenceChange((Match)target),
+ MergeViewerSide.RIGHT);
}
/**
@@ -61,7 +66,33 @@ public class MatchAccessorFactory extends AbstractAccessorFactory {
* java.lang.Object)
*/
public ITypedElement createAncestor(AdapterFactory adapterFactory, Object target) {
- return new MatchAccessor(adapterFactory, (Match)target, MergeViewerSide.ANCESTOR);
+ return new MatchAccessor(adapterFactory, (Match)target, getContainmentReferenceChange((Match)target),
+ MergeViewerSide.ANCESTOR);
}
+ /**
+ * Some Matches are related to an object that has been either added or deleted. In these cases, this
+ * method returns the Diff representing this addition or deletion. In other cases, this method returns
+ * <code>null</code>.
+ *
+ * @param match
+ * the given Match.
+ * @return the Diff on the object related to the given Match if it exists, <code>null</code> otherwise.
+ */
+ private Diff getContainmentReferenceChange(Match match) {
+ final Iterable<Diff> addOrDeleteContainmentDiffs = MatchUtil.findAddOrDeleteContainmentDiffs(match);
+ if (addOrDeleteContainmentDiffs != null) {
+ final EObject left = match.getLeft();
+ final EObject right = match.getRight();
+ final EObject origin = match.getOrigin();
+ for (Diff diff : addOrDeleteContainmentDiffs) {
+ final Object diffValue = MatchUtil.getValue(diff);
+ if (diffValue != null
+ && (diffValue.equals(left) || diffValue.equals(right) || diffValue.equals(origin))) {
+ return diff;
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/impl/MatchAccessor.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/impl/MatchAccessor.java
index a3990f153..e5b3c504d 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/impl/MatchAccessor.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/contentmergeviewer/accessor/impl/MatchAccessor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2015 Obeo.
+ * Copyright (c) 2012, 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
@@ -20,6 +20,7 @@ import java.util.Collection;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.ResourceAttachmentChange;
import org.eclipse.emf.compare.match.impl.NotLoadedFragmentMatch;
@@ -46,6 +47,9 @@ public class MatchAccessor extends AbstractTypedElementAdapter implements ICompa
/** The match associated with this accessor. */
private final Match fMatch;
+ /** The diff associated with this accessor. */
+ private Diff fDiff;
+
/** The side of this accessor. */
private final MergeViewerSide fSide;
@@ -60,8 +64,25 @@ public class MatchAccessor extends AbstractTypedElementAdapter implements ICompa
* the side of this accessor.
*/
public MatchAccessor(AdapterFactory adapterFactory, Match match, MergeViewerSide side) {
+ this(adapterFactory, match, null, side);
+ }
+
+ /**
+ * Creates a new object wrapping the given <code>eObject</code>.
+ *
+ * @param adapterFactory
+ * the adapter factory used to create the accessor.
+ * @param match
+ * the match to associate with this accessor.
+ * @param diff
+ * the diff associated with this accessor.
+ * @param side
+ * the side of this accessor.
+ */
+ public MatchAccessor(AdapterFactory adapterFactory, Match match, Diff diff, MergeViewerSide side) {
super(adapterFactory);
fMatch = match;
+ fDiff = diff;
fSide = side;
}
@@ -130,10 +151,10 @@ public class MatchAccessor extends AbstractTypedElementAdapter implements ICompa
public IMergeViewerItem getInitialItem() {
final MergeViewerItem.Container container;
if (fMatch instanceof NotLoadedFragmentMatch) {
- container = new MergeViewerItem.Container(fMatch.getComparison(), null, fMatch, fMatch, fMatch,
+ container = new MergeViewerItem.Container(fMatch.getComparison(), fDiff, fMatch, fMatch, fMatch,
fSide, getRootAdapterFactory());
} else {
- container = new MergeViewerItem.Container(fMatch.getComparison(), null, fMatch, fSide,
+ container = new MergeViewerItem.Container(fMatch.getComparison(), fDiff, fMatch, fSide,
getRootAdapterFactory());
}
return container;
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/CascadingDifferencesFilter.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/CascadingDifferencesFilter.java
index fe4d421de..ce211081a 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/CascadingDifferencesFilter.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/CascadingDifferencesFilter.java
@@ -12,29 +12,30 @@ package org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.imp
import static com.google.common.base.Predicates.and;
import static com.google.common.base.Predicates.or;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
import static org.eclipse.emf.compare.DifferenceKind.ADD;
import static org.eclipse.emf.compare.DifferenceKind.DELETE;
import static org.eclipse.emf.compare.DifferenceKind.MOVE;
-import static org.eclipse.emf.compare.DifferenceSource.LEFT;
-import static org.eclipse.emf.compare.DifferenceSource.RIGHT;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.CONTAINMENT_REFERENCE_CHANGE;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasNoDirectOrIndirectConflict;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
+import com.google.common.collect.UnmodifiableIterator;
-import java.util.Iterator;
-
+import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.Match;
-import org.eclipse.emf.compare.ReferenceChange;
import org.eclipse.emf.compare.ResourceAttachmentChange;
+import org.eclipse.emf.compare.match.MatchOfContainmentReferenceChangeAdapter;
import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.filters.AbstractDifferenceFilter;
import org.eclipse.emf.compare.utils.MatchUtil;
import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.tree.TreeNode;
/**
@@ -43,7 +44,7 @@ import org.eclipse.emf.edit.tree.TreeNode;
* Differences hidden are all those that match the following criteria:
* <ul>
* <li>this.kind != MOVE</li>
- * <li>this.conflict == null</li>
+ * <li>this.conflict == null && this.'indirect real conflicts' is empty</li>
* <li>this.refines is empty</li>
* <li>this is located inside a TreeNode that represents a Match that is either ADDed or DELETEd, and for
* which the diff that represents this addition or deletion is not refined by this.</li>
@@ -65,7 +66,8 @@ public class CascadingDifferencesFilter extends AbstractDifferenceFilter {
EObject data = treeNode.getData();
if (data instanceof Diff && !(data instanceof ResourceAttachmentChange)) {
Diff diff = (Diff)data;
- if (diff.getKind() != MOVE && diff.getConflict() == null && diff.getRefines().isEmpty()) {
+ if (diff.getKind() != MOVE && hasNoDirectOrIndirectConflict(REAL).apply(diff)
+ && diff.getRefines().isEmpty()) {
TreeNode parent = treeNode.getParent();
if (parent != null && parent.getData() instanceof Match) {
Match parentMatch = (Match)parent.getData();
@@ -94,7 +96,7 @@ public class CascadingDifferencesFilter extends AbstractDifferenceFilter {
// The ancestor has been added/deleted, we must filter the current diff
// _unless_ it is refined by the diff that represents the grand-parent
// add/delete
- ReferenceChange addOrDeleteDiff = findAddOrDeleteDiff(grandParentMatch, side);
+ Diff addOrDeleteDiff = findAddOrDeleteDiff(grandParentMatch, side);
if (addOrDeleteDiff != null) {
if (diff.getRefinedBy().contains(addOrDeleteDiff)) {
// recurse
@@ -107,14 +109,14 @@ public class CascadingDifferencesFilter extends AbstractDifferenceFilter {
return ret;
}
- private ReferenceChange findAddOrDeleteDiff(Match match, DifferenceSource side) {
- EObject container = match.eContainer();
- if (container instanceof Match) {
- @SuppressWarnings("unchecked")
- Iterator<Diff> candidates = Iterators.filter(((Match)container).getDifferences().iterator(),
- and(fromSide(side), CONTAINMENT_REFERENCE_CHANGE, ofKind(ADD, DELETE)));
- if (candidates.hasNext()) {
- return (ReferenceChange)candidates.next();
+ private Diff findAddOrDeleteDiff(Match match, DifferenceSource side) {
+ final Iterable<Diff> addOrDeleteContainmentDiffs = MatchUtil
+ .findAddOrDeleteContainmentDiffs(match);
+ if (addOrDeleteContainmentDiffs != null) {
+ final UnmodifiableIterator<Diff> sideChanges = Iterators
+ .filter(addOrDeleteContainmentDiffs.iterator(), fromSide(side));
+ if (sideChanges.hasNext()) {
+ return sideChanges.next();
}
}
return null;
@@ -134,22 +136,9 @@ public class CascadingDifferencesFilter extends AbstractDifferenceFilter {
if (match == null) {
return false;
}
- if (match.getComparison().isThreeWay()) {
- return (MatchUtil.getMatchedObject(match, side) == null) != (match.getOrigin() == null);
- }
- return (MatchUtil.getMatchedObject(match, side) == null) != (MatchUtil.getMatchedObject(match,
- opposite(side)) == null);
- }
-
- protected DifferenceSource opposite(DifferenceSource side) {
- switch (side) {
- case LEFT:
- return RIGHT;
- case RIGHT:
- return LEFT;
- default:
- throw new IllegalArgumentException("Source value not supported: " + side); //$NON-NLS-1$
- }
+ Adapter adapter = EcoreUtil.getAdapter(match.eAdapters(),
+ MatchOfContainmentReferenceChangeAdapter.class);
+ return adapter != null;
}
};
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java
index 4c7a7988e..c660a761e 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/filters/impl/TechnicalitiesFilter.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016 Obeo.
+ * Copyright (c) 2016 Obeo and others.
* 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
@@ -7,15 +7,17 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Philip Langer - bug 501864
+ * Tanja Mayerhofer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl;
+import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterators.any;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.canBeConsideredAsPseudoConflicting;
import com.google.common.base.Predicate;
-import org.eclipse.emf.compare.Conflict;
-import org.eclipse.emf.compare.ConflictKind;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.FeatureMapChange;
import org.eclipse.emf.compare.Match;
@@ -38,16 +40,6 @@ import org.eclipse.emf.edit.tree.TreeNode;
public class TechnicalitiesFilter extends AbstractDifferenceFilter {
/**
- * The predicate use by this filter when it is selected.
- */
- private static final Predicate<? super EObject> PREDICATE_WHEN_SELECTED = new Predicate<EObject>() {
- public boolean apply(EObject input) {
- return PREDICATE_EMPTY_MATCH_RESOURCES.apply(input) || PREDICATE_FEATURE_MAP.apply(input)
- || PREDICATE_IDENTICAL_ELEMENTS.apply(input) || PREDICATE_PSEUDO_CONFLICT.apply(input);
- }
- };
-
- /**
* The predicate use to filter empty match resources.
*/
private static final Predicate<? super EObject> PREDICATE_EMPTY_MATCH_RESOURCES = new Predicate<EObject>() {
@@ -91,8 +83,7 @@ public class TechnicalitiesFilter extends AbstractDifferenceFilter {
if (data instanceof Diff) {
Diff diff = (Diff)data;
if (diff.getMatch().getComparison().isThreeWay()) {
- Conflict conflict = diff.getConflict();
- ret = conflict != null && conflict.getKind() == ConflictKind.PSEUDO;
+ ret = canBeConsideredAsPseudoConflicting().apply(diff);
}
}
}
@@ -117,6 +108,14 @@ public class TechnicalitiesFilter extends AbstractDifferenceFilter {
};
/**
+ * The predicate use by this filter when it is selected.
+ */
+ @SuppressWarnings("unchecked")
+ private static final Predicate<? super EObject> PREDICATE_WHEN_SELECTED = or(
+ PREDICATE_EMPTY_MATCH_RESOURCES, PREDICATE_FEATURE_MAP, PREDICATE_IDENTICAL_ELEMENTS,
+ PREDICATE_PSEUDO_CONFLICT);
+
+ /**
* Predicate to know if the given TreeNode is a diff.
*/
private static final Predicate<EObject> DATA_IS_DIFF = new Predicate<EObject>() {
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java
index 7eec360ef..60664fa94 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/groups/impl/ThreeWayComparisonGroupProvider.java
@@ -9,34 +9,55 @@
* Obeo - initial API and implementation
* Stefan Dirix - bug 488941
* Simon Delisle, Edgar Mueller - bug 486923
+ * Tanja Mayerhofer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.and;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.base.Predicates.or;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterators.concat;
import static com.google.common.collect.Iterators.filter;
import static com.google.common.collect.Iterators.transform;
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
+import static java.util.Collections.unmodifiableSet;
+import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
+import static org.eclipse.emf.compare.internal.utils.DiffUtil.getRootRefinedDiffs;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.allAtomicRefining;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.anyRefining;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.containsConflictOfTypes;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasConflict;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasState;
import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
import com.google.common.collect.UnmodifiableIterator;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
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.DifferenceState;
+import org.eclipse.emf.compare.impl.ConflictImpl;
import org.eclipse.emf.compare.provider.utils.ComposedStyledString;
import org.eclipse.emf.compare.provider.utils.IStyledString;
import org.eclipse.emf.compare.provider.utils.IStyledString.IComposedStyledString;
@@ -55,6 +76,45 @@ import org.eclipse.emf.ecore.util.EcoreUtil;
* This implementation of a
* {@link org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroupProvider} will be used to
* group the differences by their {@link DifferenceSource side} : left, right and conflicts.
+ * <p>
+ * The table below describes the location of a diff depending on its status and that of its refining diffs
+ * (whether all or some of them are in a real/pseudo conflict). <br/>
+ * <br/>
+ * <table style="border-collapse:collapse;">
+ * <thead>
+ * <tr>
+ * <th rowspan="2"></th>
+ * <th colspan="2" style="border:1px solid;">Real Conflicts</th>
+ * <th colspan="2" style="border:1px solid;">Pseudo-Conflicts</th>
+ * <th style="border:1px solid;">No Conflict</th>
+ * </tr>
+ * <tr>
+ * <th style="border:1px solid;">All</th>
+ * <th style="border:1px solid;">Some</th>
+ * <th style="border:1px solid;">All</th>
+ * <th style="border:1px solid;">Some</th>
+ * <th style="border:1px solid;">All</th>
+ * </tr>
+ * </thead> <tbody>
+ * <tr>
+ * <td style="border:1px solid; padding:0 2px;">Tech. filter ON</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict (hidden)</td>
+ * <td style="border:1px solid; padding:0 2px;">Side</td>
+ * <td style="border:1px solid; padding:0 2px;">Side</td>
+ * </tr>
+ * <tr>
+ * <td style="border:1px solid; padding:0 2px;">Tech. filter OFF</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Conflict</td>
+ * <td style="border:1px solid; padding:0 2px;">Side</td>
+ * <td style="border:1px solid; padding:0 2px;">Side</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * </p>
*
* @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
* @since 4.0
@@ -62,6 +122,14 @@ import org.eclipse.emf.ecore.util.EcoreUtil;
public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProvider {
/**
+ * The default predicate used to filter differences in difference groups. The predicate returns true for
+ * diffs that do not have a direct or indirect real conflict and that do not have only pseudo conflicts.
+ */
+ public static final Predicate<? super Diff> DEFAULT_DIFF_GROUP_FILTER_PREDICATE = and(
+ not(hasConflict(REAL, PSEUDO)),
+ not(or(anyRefining(hasConflict(REAL)), allAtomicRefining(hasConflict(PSEUDO)))));
+
+ /**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.rcp.ui.structuremergeviewer.groups.IDifferenceGroupProvider#isEnabled(org
@@ -83,6 +151,22 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
public static class ConflictsGroupImpl extends BasicDifferenceGroupImpl {
/**
+ * The default predicate used to filter differences.
+ */
+ private static final Predicate<? super Diff> DEFAULT_CONFLICT_GROUP_FILTER_PREDICATE = hasConflict(
+ ConflictKind.REAL, ConflictKind.PSEUDO);
+
+ /**
+ * Conflict groups to show in SMV.
+ */
+ private final List<CompositeConflict> compositeConflicts = newArrayList();
+
+ /**
+ * Maps conflicting differences to their composite conflicts.
+ */
+ private final Map<Diff, CompositeConflict> diffToCompositeConflictMap = newHashMap();
+
+ /**
* {@inheritDoc}.
*
* @see org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.BasicDifferenceGroupImpl#BasicDifferenceGroupImpl(org.eclipse.emf.compare.Comparison,
@@ -94,6 +178,22 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
}
/**
+ * Instantiates this group given the comparison. It will use the default filter to determine its list
+ * of differences. It will be displayed in the UI with the default icon and the given name.
+ *
+ * @param comparison
+ * The comparison that is the parent of this group.
+ * @param name
+ * The name that the EMF Compare UI will display for this group.
+ * @param crossReferenceAdapter
+ * The cross reference adapter that will be added to this group's children.
+ */
+ public ConflictsGroupImpl(Comparison comparison, String name,
+ ECrossReferenceAdapter crossReferenceAdapter) {
+ super(comparison, DEFAULT_CONFLICT_GROUP_FILTER_PREDICATE, name, crossReferenceAdapter);
+ }
+
+ /**
* In conflicts, a special case must be handled for refining diffs: If they are not part of the same
* conflict then they should not be in the same group as the refined diff.
*
@@ -111,13 +211,53 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
@Override
protected void doBuildSubTrees() {
for (Conflict conflict : getComparison().getConflicts()) {
- ConflictNodeBuilder builder = new ConflictNodeBuilder(conflict, this);
- ConflictNode conflictNode = builder.buildNode();
+ final CompositeConflict compositeConflict = new CompositeConflict(conflict);
+ compositeConflicts.add(compositeConflict);
+ joinOverlappingCompositeConflicts(compositeConflict);
+ updateDiffToCompositeConflictMap(compositeConflict);
+ }
+
+ for (CompositeConflict conflict : compositeConflicts) {
+ final ConflictNodeBuilder builder = new ConflictNodeBuilder(conflict, this);
+ final ConflictNode conflictNode = builder.buildNode();
children.add(conflictNode);
}
}
/**
+ * Joins the given composite conflict with existing overlapping composite conflicts.
+ *
+ * @param compositeConflict
+ * The composite conflict into which overlapping composite conflicts should be joined
+ */
+ private void joinOverlappingCompositeConflicts(final CompositeConflict compositeConflict) {
+ // determine composite conflicts to join
+ final Set<CompositeConflict> compositeConflictsToJoin = new HashSet<CompositeConflict>();
+ for (Diff diff : compositeConflict.getDifferences()) {
+ if (diffToCompositeConflictMap.containsKey(diff)) {
+ compositeConflictsToJoin.add(diffToCompositeConflictMap.get(diff));
+ }
+ }
+ // join conflict groups
+ for (CompositeConflict conflictGroupToJoin : compositeConflictsToJoin) {
+ compositeConflict.join(conflictGroupToJoin);
+ compositeConflicts.remove(conflictGroupToJoin);
+ }
+ }
+
+ /**
+ * Updates the diff to composite conflict map with the given composite conflict.
+ *
+ * @param compositeConflict
+ * The composite conflict that should be added to the diff to composite conflict map
+ */
+ private void updateDiffToCompositeConflictMap(final CompositeConflict compositeConflict) {
+ for (Diff diff : compositeConflict.getDifferences()) {
+ diffToCompositeConflictMap.put(diff, compositeConflict);
+ }
+ }
+
+ /**
* {@inheritDoc}
*
* @see org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.BasicDifferenceGroupImpl#getStyledName()
@@ -140,15 +280,112 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
}
/**
- * {@inheritDoc}
+ * This extension of {@link Conflict} is used to handle {@link Diff#getRefinedBy() refined} diffs and to
+ * join conflicts for the SMV. If refining diffs are part of a conflict, we show their refined diffs
+ * instead. As we show refined diffs instead of the refining diffs, multiple conflicts may consequently
+ * include the same refined diffs. To avoid that, this extension of a conflict also joins such overlapping
+ * conflicts.
*
- * @see org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.AbstractBuildingDifferenceGroupProvider#buildGroups(org.eclipse.emf.compare.Comparison)
+ * @author <a href="mailto:tmayerhofer@eclipsesource.com">Tanja Mayerhofer</a>
*/
+ public static class CompositeConflict extends ConflictImpl {
+
+ /** The joined conflicts. */
+ private Set<Conflict> conflicts = new LinkedHashSet<Conflict>();
+
+ /** The diffs of all composed conflicts. */
+ private EList<Diff> diffs = new BasicEList<Diff>();
+
+ /** The conflict kind of this composite conflict. */
+ private ConflictKind conflictKind = ConflictKind.REAL;
+
+ /**
+ * Creates a new composite conflict for the given conflict.
+ *
+ * @param conflict
+ * The conflict to create a composite conflict for, must not be <code>null</code> and must
+ * have a non-<code>null</code> {@link Conflict#getKind() kind}.
+ */
+ public CompositeConflict(Conflict conflict) {
+ conflicts.add(checkNotNull(conflict));
+ conflictKind = checkNotNull(conflict.getKind());
+ diffs.addAll(computeRefinedDiffs(conflict));
+ }
+
+ /**
+ * Computes the refined diffs of the conflict. In particular, refining diffs are replaced by refined
+ * diffs.
+ *
+ * @param conflict
+ * The conflict to compute its refined diffs for.
+ * @return The set of refined diffs of the conflict
+ */
+ private Set<Diff> computeRefinedDiffs(Conflict conflict) {
+ Set<Diff> computedDiffs = new LinkedHashSet<Diff>();
+ for (Diff diff : conflict.getDifferences()) {
+ if (diff.getRefines().isEmpty()) {
+ computedDiffs.add(diff);
+ } else {
+ computedDiffs.addAll(getRootRefinedDiffs(diff));
+ }
+ }
+ return computedDiffs;
+ }
+
+ @Override
+ public ConflictKind getKind() {
+ return conflictKind;
+ }
+
+ /**
+ * Returns an EList built by aggregating the diffs of all the aggregated conflicts.
+ * <p>
+ * <b>This list is not supposed to be used for update, since modifying this list will not modify the
+ * underlying conflicts.</b>
+ * </p>
+ */
+ @Override
+ public EList<Diff> getDifferences() {
+ return diffs;
+ }
+
+ /**
+ * Returns an unmodifiable view of the joined conflicts.
+ *
+ * @return An unmodifiable view of the joined conflicts, never <code>null</code> nor empty.
+ */
+ public Set<Conflict> getConflicts() {
+ return unmodifiableSet(conflicts);
+ }
+
+ /**
+ * Joins the provided composite conflict with this composite conflict.
+ *
+ * @param conflict
+ * The conflict to be joined with this composite conflict
+ */
+ public void join(CompositeConflict conflict) {
+ Set<Diff> currentDiffSet = new LinkedHashSet<Diff>(diffs);
+ Set<Diff> otherDiffSet = new LinkedHashSet<Diff>(conflict.getDifferences());
+ SetView<Diff> newDiffs = Sets.difference(otherDiffSet, currentDiffSet);
+ diffs.addAll(newDiffs);
+ if (conflicts.addAll(conflict.getConflicts()) && conflictKind != REAL) {
+ if (any(conflicts, containsConflictOfTypes(REAL))) {
+ conflictKind = REAL;
+ } else {
+ conflictKind = PSEUDO;
+ }
+ }
+ }
+ }
+
@Override
protected Collection<? extends IDifferenceGroup> buildGroups(Comparison comparison2) {
Adapter adapter = EcoreUtil.getAdapter(getComparison().eAdapters(), SideLabelProvider.class);
- final String leftLabel, rightLabel;
+ final String leftLabel;
+ final String rightLabel;
+
if (adapter instanceof SideLabelProvider) {
SideLabelProvider labelProvider = (SideLabelProvider)adapter;
leftLabel = labelProvider.getLeftLabel();
@@ -159,21 +396,18 @@ public class ThreeWayComparisonGroupProvider extends AbstractDifferenceGroupProv
}
final ConflictsGroupImpl conflicts = new ConflictsGroupImpl(getComparison(),
- hasConflict(ConflictKind.REAL, ConflictKind.PSEUDO),
EMFCompareRCPUIMessages.getString("ThreeWayComparisonGroupProvider.conflicts.label"), //$NON-NLS-1$
getCrossReferenceAdapter());
conflicts.buildSubTree();
final BasicDifferenceGroupImpl leftSide = new BasicDifferenceGroupImpl(getComparison(),
- Predicates.and(fromSide(DifferenceSource.LEFT),
- Predicates.not(hasConflict(ConflictKind.REAL, ConflictKind.PSEUDO))),
- leftLabel, getCrossReferenceAdapter());
+ and(fromSide(DifferenceSource.LEFT), DEFAULT_DIFF_GROUP_FILTER_PREDICATE), leftLabel,
+ getCrossReferenceAdapter());
leftSide.buildSubTree();
final BasicDifferenceGroupImpl rightSide = new BasicDifferenceGroupImpl(getComparison(),
- Predicates.and(fromSide(DifferenceSource.RIGHT),
- Predicates.not(hasConflict(ConflictKind.REAL, ConflictKind.PSEUDO))),
- rightLabel, getCrossReferenceAdapter());
+ and(fromSide(DifferenceSource.RIGHT), DEFAULT_DIFF_GROUP_FILTER_PREDICATE), rightLabel,
+ getCrossReferenceAdapter());
rightSide.buildSubTree();
return ImmutableList.of(conflicts, leftSide, rightSide);
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/match/MatchOfContainmentReferenceChangeProcessor.java b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/match/MatchOfContainmentReferenceChangeProcessor.java
new file mode 100644
index 000000000..38a9fefc9
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.rcp.ui/src/org/eclipse/emf/compare/rcp/ui/internal/structuremergeviewer/match/MatchOfContainmentReferenceChangeProcessor.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 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.rcp.ui.internal.structuremergeviewer.match;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.ReferenceChange;
+import org.eclipse.emf.compare.match.MatchOfContainmentReferenceChangeAdapter;
+import org.eclipse.emf.compare.utils.EMFComparePredicates;
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * Process a comparison to detect {@link Match}es related to containment ReferenceChange. Add a
+ * {@link MatchOfContainmentReferenceChangeAdapter} on such Matches.
+ *
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public class MatchOfContainmentReferenceChangeProcessor {
+
+ /**
+ * Constructor.
+ */
+ public MatchOfContainmentReferenceChangeProcessor() {
+ }
+
+ /**
+ * Check for the given {@link Comparison}, if {@link Match}es are related to a containment
+ * ReferenceChange. If it is add a {@link MatchOfContainmentReferenceChangeAdapter} to these
+ * {@link Match}es.
+ *
+ * @param comp
+ * The {@link Comparison} to check.
+ */
+ public void execute(Comparison comp) {
+ for (Match rootMatch : comp.getMatches()) {
+ checkForMatchRelatedToContainmentReferenceChange(rootMatch);
+ }
+ }
+
+ /**
+ * Check if the given {@link Match} is related to a containment ReferenceChange. If it is add a
+ * {@link MatchOfContainmentReferenceChangeAdapter} to this {@link Match}. Also check for all sub-matches
+ * of the given {@link Match}.
+ *
+ * @param match
+ * The {@link Match} to check
+ */
+ protected void checkForMatchRelatedToContainmentReferenceChange(Match match) {
+ EObject parentMatch = match.eContainer();
+ if (parentMatch instanceof Match) {
+ EList<Diff> differences = ((Match)parentMatch).getDifferences();
+ for (Diff parentMatchDiff : differences) {
+ if (EMFComparePredicates.CONTAINMENT_REFERENCE_CHANGE.apply(parentMatchDiff)) {
+ EObject value = ((ReferenceChange)parentMatchDiff).getValue();
+ if (value != null && (value.equals(match.getLeft()) || value.equals(match.getRight())
+ || value.equals(match.getOrigin()))) {
+ match.eAdapters().add(new MatchOfContainmentReferenceChangeAdapter(
+ (ReferenceChange)parentMatchDiff));
+ break;
+ }
+ }
+ }
+ }
+ for (Match subMatch : match.getSubmatches()) {
+ checkForMatchRelatedToContainmentReferenceChange(subMatch);
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
index 38afa7a79..4a1003a90 100644
--- a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java
@@ -13,10 +13,6 @@
*******************************************************************************/
package org.eclipse.emf.compare.tests.suite;
-import junit.framework.JUnit4TestAdapter;
-import junit.framework.Test;
-import junit.textui.TestRunner;
-
import org.eclipse.emf.compare.ComparePackage;
import org.eclipse.emf.compare.tests.command.CommandStackTestSuite;
import org.eclipse.emf.compare.tests.conflict.ConflictDetectionTest;
@@ -65,6 +61,7 @@ import org.eclipse.emf.compare.tests.postprocess.PostProcessorTest;
import org.eclipse.emf.compare.tests.req.ReqComputingTest;
import org.eclipse.emf.compare.tests.scope.ComparisonScopeAdapterTest;
import org.eclipse.emf.compare.tests.scope.DefaultComparisonScopeTest;
+import org.eclipse.emf.compare.tests.utils.EMFComparePredicatesTest;
import org.eclipse.emf.compare.tests.utils.EqualityHelperTest;
import org.eclipse.emf.compare.tests.utils.MatchUtilFeatureContainsTest;
import org.eclipse.emf.ecore.EPackage;
@@ -74,6 +71,10 @@ import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.textui.TestRunner;
+
/**
* This test suite allows us to launch all tests for EMF Compare at once.
*
@@ -96,7 +97,7 @@ import org.junit.runners.Suite.SuiteClasses;
MultiLineAttributeMergeTest.class, MonitorCancelTest.class, IdentifierEObjectMatcherTest.class,
MatchUtilFeatureContainsTest.class, RefineMergeTest.class, Bug484557ConflictTest.class,
Bug485266_MoveDeleteConflict_Test.class, ResourceAttachmentChangeBug492261.class,
- ComparisonScopeAdapterTest.class, })
+ ComparisonScopeAdapterTest.class, EMFComparePredicatesTest.class, })
public class AllTests {
/**
* Standalone launcher for all of compare's tests.
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/EMFComparePredicatesTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/EMFComparePredicatesTest.java
new file mode 100644
index 000000000..679ba6db1
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/EMFComparePredicatesTest.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 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.utils;
+
+import static com.google.common.base.Predicates.equalTo;
+import static com.google.common.base.Predicates.instanceOf;
+import static java.util.Arrays.asList;
+import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.allAtomicRefining;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.anyRefining;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasNoDirectOrIndirectConflict;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.compare.AttributeChange;
+import org.eclipse.emf.compare.CompareFactory;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Conflict;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.ReferenceChange;
+import org.junit.Test;
+
+public class EMFComparePredicatesTest {
+
+ private CompareFactory factory = CompareFactory.eINSTANCE;
+
+ @Test
+ public void testAnyRefiningWithoutRecursion() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+
+ AttributeChange ac = factory.createAttributeChange();
+ ReferenceChange rc1 = factory.createReferenceChange();
+ ReferenceChange rc2 = factory.createReferenceChange();
+ ReferenceChange rc3 = factory.createReferenceChange();
+ EList<Diff> diffs = rootMatch.getDifferences();
+ diffs.add(ac);
+ diffs.add(rc1);
+ diffs.add(rc2);
+ diffs.add(rc3);
+ ac.getRefinedBy().addAll(asList(rc1, rc2, rc3));
+
+ assertFalse(anyRefining(instanceOf(AttributeChange.class)).apply(ac));
+ assertTrue(anyRefining(instanceOf(ReferenceChange.class)).apply(ac));
+ assertTrue(anyRefining(equalTo((Diff)rc3)).apply(ac));
+ }
+
+ @Test
+ public void testAnyRefiningWithRecursion() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+
+ AttributeChange ac = factory.createAttributeChange();
+ AttributeChange ac1 = factory.createAttributeChange();
+ ReferenceChange rc11 = factory.createReferenceChange();
+ ReferenceChange rc12 = factory.createReferenceChange();
+ ReferenceChange rc2 = factory.createReferenceChange();
+ ReferenceChange rc3 = factory.createReferenceChange();
+ EList<Diff> diffs = rootMatch.getDifferences();
+ diffs.add(ac);
+ diffs.add(ac1);
+ diffs.add(rc11);
+ diffs.add(rc12);
+ diffs.add(rc2);
+ diffs.add(rc3);
+ ac.getRefinedBy().addAll(asList(ac1, rc2, rc3));
+ ac1.getRefinedBy().addAll(asList(rc11, rc12));
+
+ assertTrue(anyRefining(instanceOf(AttributeChange.class)).apply(ac));
+ assertTrue(anyRefining(instanceOf(ReferenceChange.class)).apply(ac));
+ assertTrue(anyRefining(equalTo((Diff)rc12)).apply(ac));
+ assertFalse(anyRefining(equalTo((Diff)ac)).apply(ac));
+ }
+
+ @Test
+ public void testAllAtomicRefiningWithoutRecursion() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+
+ AttributeChange ac = factory.createAttributeChange();
+ ReferenceChange rc1 = factory.createReferenceChange();
+ ReferenceChange rc2 = factory.createReferenceChange();
+ ReferenceChange rc3 = factory.createReferenceChange();
+ EList<Diff> diffs = rootMatch.getDifferences();
+ diffs.add(ac);
+ diffs.add(rc1);
+ diffs.add(rc2);
+ diffs.add(rc3);
+ ac.getRefinedBy().addAll(asList(rc1, rc2, rc3));
+
+ assertFalse(allAtomicRefining(instanceOf(AttributeChange.class)).apply(ac));
+ assertTrue(allAtomicRefining(instanceOf(ReferenceChange.class)).apply(ac));
+ assertFalse(allAtomicRefining(equalTo((Diff)rc3)).apply(ac));
+ }
+
+ @Test
+ public void testAllAtomicRefiningWithRecursion() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+
+ AttributeChange ac = factory.createAttributeChange();
+ AttributeChange ac1 = factory.createAttributeChange();
+ ReferenceChange rc11 = factory.createReferenceChange();
+ ReferenceChange rc12 = factory.createReferenceChange();
+ ReferenceChange rc2 = factory.createReferenceChange();
+ ReferenceChange rc3 = factory.createReferenceChange();
+ EList<Diff> diffs = rootMatch.getDifferences();
+ diffs.add(ac);
+ diffs.add(ac1);
+ diffs.add(rc11);
+ diffs.add(rc12);
+ diffs.add(rc2);
+ diffs.add(rc3);
+ ac.getRefinedBy().addAll(asList(ac1, rc2, rc3));
+ ac1.getRefinedBy().addAll(asList(rc11, rc12));
+
+ assertFalse(allAtomicRefining(instanceOf(AttributeChange.class)).apply(ac));
+ assertTrue(allAtomicRefining(instanceOf(ReferenceChange.class)).apply(ac));
+ assertFalse(allAtomicRefining(equalTo((Diff)rc12)).apply(ac));
+ }
+
+ @Test
+ public void testHasDirectOrIndirectConflictForDirectConflict() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+ AttributeChange acl = factory.createAttributeChange();
+ AttributeChange acr = factory.createAttributeChange();
+ rootMatch.getDifferences().addAll(asList(acl, acr));
+ Conflict conflict = factory.createConflict();
+ conflict.setKind(REAL);
+ conflict.getDifferences().addAll(asList(acl, acr));
+ comp.getConflicts().add(conflict);
+
+ assertTrue(hasDirectOrIndirectConflict(REAL).apply(acl));
+ assertTrue(hasDirectOrIndirectConflict(REAL).apply(acr));
+ assertFalse(hasDirectOrIndirectConflict(PSEUDO).apply(acl));
+ assertFalse(hasDirectOrIndirectConflict(PSEUDO).apply(acr));
+
+ assertFalse(hasNoDirectOrIndirectConflict(REAL).apply(acl));
+ assertFalse(hasNoDirectOrIndirectConflict(REAL).apply(acr));
+ assertTrue(hasNoDirectOrIndirectConflict(PSEUDO).apply(acl));
+ assertTrue(hasNoDirectOrIndirectConflict(PSEUDO).apply(acr));
+ }
+
+ @Test
+ public void testHasDirectOrIndirectConflictForIndirectConflict() {
+ Comparison comp = factory.createComparison();
+ Match rootMatch = factory.createMatch();
+ comp.getMatches().add(rootMatch);
+ ReferenceChange rc = factory.createReferenceChange();
+ AttributeChange acl = factory.createAttributeChange();
+ AttributeChange acr = factory.createAttributeChange();
+ rootMatch.getDifferences().addAll(asList(rc, acl, acr));
+ rc.getRefinedBy().addAll(asList(acl));
+ Conflict conflict = factory.createConflict();
+ conflict.setKind(REAL);
+ conflict.getDifferences().addAll(asList(acl, acr));
+ comp.getConflicts().add(conflict);
+
+ assertTrue(hasDirectOrIndirectConflict(REAL).apply(rc));
+ assertFalse(hasDirectOrIndirectConflict(PSEUDO).apply(rc));
+ assertFalse(hasNoDirectOrIndirectConflict(REAL).apply(rc));
+ assertTrue(hasNoDirectOrIndirectConflict(PSEUDO).apply(rc));
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/GraphTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/GraphTest.java
index aa9981c4c..02e10f59f 100644
--- a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/GraphTest.java
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/utils/GraphTest.java
@@ -38,11 +38,19 @@ public class GraphTest {
@Test
public void testBuildSubGraph() {
IGraph<String> graph = new Graph<String>();
- // @formatter:off
- /*
- * Add the following graph: e f | | b c d \ | / \ | / --------- | a
+ /**
+ * <pre>
+ * Add the following graph:
+ * e f
+ * | |
+ * b c d
+ * \ | /
+ * \ | /
+ * ---------
+ * |
+ * a
+ * </pre>
*/
- // @formatter:on
graph.addChildren("a", ImmutableSet.of("b", "c", "d"));
graph.addChildren("c", ImmutableSet.of("e"));
graph.addChildren("d", ImmutableSet.of("f"));
@@ -58,11 +66,16 @@ public class GraphTest {
@Test
public void testPrune() {
IGraph<String> graph = new Graph<String>();
- // @formatter:off
- /*
- * Add the following graph: c-\ | | b-/ | a
+ /**
+ * <pre>
+ * Add the following graph:
+ * c-\
+ * | |
+ * b-/
+ * |
+ * a
+ * </pre>
*/
- // @formatter:on
graph.addChildren("a", ImmutableSet.of("b"));
graph.addChildren("b", ImmutableSet.of("c"));
graph.addChildren("c", ImmutableSet.of("b"));
@@ -76,13 +89,22 @@ public class GraphTest {
@Test
public void testBreadthFirstIteration() {
IGraph<String> graph = new Graph<String>();
- // @formatter:off
- /*
- * With the following Graph: A I J / \ / / \ B C G K L / / \ / \ / \ D E F H M N We expect our
- * iteration to go in the following order: three first items, in unspecified order : A, I, J next
- * five, in unspecified order : B, C, G, K, L finally, still in unspecified order : D, E, F, H, M, N
+ /**
+ * <pre>
+ * With the following Graph:
+ *
+ * A I J
+ * / \ / / \
+ * B C G K L
+ * / / \ / \ / \
+ * D E F H M N
+ *
+ * We expect our iteration to go in the following order:
+ * three first items, in unspecified order : A, I, J
+ * next five, in unspecified order : B, C, G, K, L
+ * finally, still in unspecified order : D, E, F, H, M, N
+ * </pre>
*/
- // @formatter:on
graph.addChildren("A", ImmutableSet.of("B", "C"));
graph.addChildren("B", ImmutableSet.of("D"));
graph.addChildren("C", ImmutableSet.of("E", "F"));
@@ -228,6 +250,125 @@ public class GraphTest {
}
/**
+ * Test the BreadthFirstIterator with the following cyclic graph:
+ *
+ * <pre>
+ * A
+ * / \
+ * B = C
+ * </pre>
+ */
+ @Test
+ public void testBug503035_1() {
+ IGraph<String> graph = new Graph<String>();
+
+ graph.addChildren("A", ImmutableSet.of("B", "C"));
+ graph.addChildren("B", ImmutableSet.of("C"));
+ graph.addChildren("C", ImmutableSet.of("B"));
+
+ Iterator<String> it = graph.breadthFirstIterator();
+ assertTrue(it.hasNext());
+ assertEquals("A", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("B", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("C", it.next());
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * Test the BreadthFirstIterator with the following cyclic graph:
+ *
+ * <pre>
+ * A
+ * / \
+ * B = C
+ * /
+ * D
+ * </pre>
+ */
+ @Test
+ public void testBug503035_2() {
+ IGraph<String> graph = new Graph<String>();
+
+ graph.addChildren("A", ImmutableSet.of("B", "C"));
+ graph.addChildren("B", ImmutableSet.of("D", "C"));
+ graph.addChildren("C", ImmutableSet.of("B"));
+
+ Iterator<String> it = graph.breadthFirstIterator();
+ assertTrue(it.hasNext());
+ assertEquals("A", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("B", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("C", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("D", it.next());
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * Test the BreadthFirstIterator with the following cyclic graph:
+ *
+ * <pre>
+ * A B
+ * | |
+ * C = D
+ * </pre>
+ */
+ @Test
+ public void testBug503035_3() {
+ IGraph<String> graph = new Graph<String>();
+
+ graph.addChildren("A", ImmutableSet.of("C"));
+ graph.addChildren("B", ImmutableSet.of("D"));
+ graph.addChildren("C", ImmutableSet.of("D"));
+ graph.addChildren("D", ImmutableSet.of("C"));
+
+ Iterator<String> it = graph.breadthFirstIterator();
+ assertTrue(it.hasNext());
+ assertEquals("A", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("B", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("C", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("D", it.next());
+ assertFalse(it.hasNext());
+ }
+
+ /**
+ * Test the BreadthFirstIterator with the following cyclic graph:
+ *
+ * <pre>
+ * A
+ * /|\
+ * / | \
+ * B C D
+ * \\===//
+ * </pre>
+ */
+ @Test
+ public void testBug503035_4() {
+ IGraph<String> graph = new Graph<String>();
+
+ graph.addChildren("A", ImmutableSet.of("B", "C", "D"));
+ graph.addChildren("B", ImmutableSet.of("D"));
+ graph.addChildren("D", ImmutableSet.of("B"));
+
+ Iterator<String> it = graph.breadthFirstIterator();
+ assertTrue(it.hasNext());
+ assertEquals("A", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("B", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("C", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("D", it.next());
+ assertFalse(it.hasNext());
+ }
+
+ /**
* @return The following acyclic graph:
*
* <pre>
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/META-INF/MANIFEST.MF
index 48e5c73af..c952a8367 100644
--- a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/META-INF/MANIFEST.MF
@@ -16,7 +16,8 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.emf.compare.uml2.rcp.ui;bundle-version="2.2.0",
org.eclipse.uml2.uml.resources,
org.eclipse.emf.compare.uml2.tests,
- org.eclipse.emf.compare.rcp
+ org.eclipse.emf.compare.rcp,
+ org.eclipse.emf.compare.rcp.ui.tests;bundle-version="4.3.0"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Bundle-ActivationPolicy: lazy
Bundle-Localization: plugin
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/ConflictsGroupTest.java b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/ConflictsGroupTest.java
new file mode 100644
index 000000000..bea16fbe8
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/ConflictsGroupTest.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Obeo and others.
+ * 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
+ * Tanja Mayerhofer - bug 501864
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.rcp.ui.tests.groups;
+
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasConflict;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Lists;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Conflict;
+import org.eclipse.emf.compare.ConflictKind;
+import org.eclipse.emf.compare.provider.spec.CompareItemProviderAdapterFactorySpec;
+import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareRCPUIMessages;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.CompositeConflict;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.groups.impl.ThreeWayComparisonGroupProvider.ConflictsGroupImpl;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.ConflictNode;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.DiffNode;
+import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.nodes.MatchNode;
+import org.eclipse.emf.compare.rcp.ui.tests.structuremergeviewer.groups.provider.AbstractTestTreeNodeItemProviderAdapter;
+import org.eclipse.emf.compare.uml2.rcp.ui.tests.groups.data.uml.compositeconflict.UMLJoiningConflictsWithOverlappingDiffsInputData;
+import org.eclipse.emf.compare.uml2.rcp.ui.tests.groups.data.uml.conflictrefiningdiffs.UMLConflictWithRefiningDiffInputData;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
+import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
+import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
+import org.eclipse.emf.edit.tree.TreeNode;
+import org.eclipse.emf.edit.tree.TreePackage;
+import org.junit.Test;
+
+@SuppressWarnings("restriction")
+public class ConflictsGroupTest extends AbstractTestTreeNodeItemProviderAdapter {
+
+ private AdapterFactoryItemDelegator itemDelegator;
+
+ @Override
+ public void before() throws IOException {
+ super.before();
+
+ final Collection<AdapterFactory> factories = Lists.newArrayList();
+ factories.add(new CompareItemProviderAdapterFactorySpec());
+ factories.add(treeItemProviderAdapterFactory);
+ factories.add(new EcoreItemProviderAdapterFactory());
+ factories.add(new ReflectiveItemProviderAdapterFactory());
+
+ final AdapterFactory composedAdapterFactory = new ComposedAdapterFactory(factories);
+ itemDelegator = new AdapterFactoryItemDelegator(composedAdapterFactory);
+ }
+
+ /**
+ * Tests that for conflicts containing refining diffs, the refining diffs are replaced with their refined
+ * diffs when displayed in the SMV. This test is related to <a
+ * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testReplacementOfRefiningDiffs() throws IOException {
+ Comparison comparison = getComparison(new UMLConflictWithRefiningDiffInputData());
+ ECrossReferenceAdapter crossReferenceAdapter = new ECrossReferenceAdapter() {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.ecore.util.ECrossReferenceAdapter#isIncluded(org.eclipse.emf.ecore.EReference)
+ */
+ @Override
+ protected boolean isIncluded(EReference eReference) {
+ return eReference == TreePackage.Literals.TREE_NODE__DATA;
+ }
+ };
+ final ConflictsGroupImpl conflictsGroup = new ConflictsGroupImpl(comparison,
+ hasConflict(ConflictKind.REAL, ConflictKind.PSEUDO),
+ EMFCompareRCPUIMessages.getString("ThreeWayComparisonGroupProvider.conflicts.label"), //$NON-NLS-1$
+ crossReferenceAdapter);
+ conflictsGroup.buildSubTree();
+
+ List<? extends TreeNode> conflictNodes = conflictsGroup.getChildren();
+ assertEquals(1, conflictNodes.size());
+
+ ConflictNode conflictNode = (ConflictNode)conflictNodes.get(0);
+ List<? extends TreeNode> matchNodes = conflictNode.getChildren();
+ assertEquals(1, matchNodes.size());
+
+ // Match node for OpauqeAction
+ MatchNode matchNode = (MatchNode)matchNodes.get(0);
+ checkText(matchNode, "Opaque Action OpaqueAction"); //$NON-NLS-1$
+
+ List<? extends TreeNode> diffNodes = matchNode.getChildren();
+ assertEquals(2, diffNodes.size());
+
+ // Diff node for deletion of OpaqueAction
+ DiffNode diffNodeDeletion = (DiffNode)diffNodes.get(0);
+ checkText(diffNodeDeletion, "Opaque Action OpaqueAction [ownedNode delete]"); //$NON-NLS-1$
+ assertEquals(0, diffNodeDeletion.getChildren().size());
+
+ // Diff node for opaque element change of OpaqueAction
+ DiffNode diffNodeChange = (DiffNode)diffNodes.get(1);
+ checkText(diffNodeChange, "Opaque Element Body Change Natural language"); //$NON-NLS-1$
+
+ List<? extends TreeNode> diffNodeChildren = diffNodeChange.getChildren();
+ assertEquals(2, diffNodeChildren.size());
+
+ // Diff node for body add of OpaqueAction
+ DiffNode diffNodeBodyAdd = (DiffNode)diffNodeChildren.get(0);
+ checkText(diffNodeBodyAdd, "This is a natural language definition of Opaque... [body add]"); //$NON-NLS-1$
+ assertEquals(0, diffNodeBodyAdd.getChildren().size());
+
+ // Diff node for language add of OpaqueAction
+ DiffNode diffNodeLanguageAdd = (DiffNode)diffNodeChildren.get(1);
+ checkText(diffNodeLanguageAdd, "Natural language [language add]"); //$NON-NLS-1$
+ assertEquals(0, diffNodeLanguageAdd.getChildren().size());
+ }
+
+ /**
+ * Tests that conflicts containing overlapping diffs are joined in the SMV. Overlapping diffs can happen
+ * due to the replacement of refining diffs with their refined diffs in the SMV. This test is related to
+ * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=501864"</a>
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testJoiningConflictsWithOverlappingDiffs() throws IOException {
+ Comparison comparison = getComparison(new UMLJoiningConflictsWithOverlappingDiffsInputData());
+ ECrossReferenceAdapter crossReferenceAdapter = new ECrossReferenceAdapter() {
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.ecore.util.ECrossReferenceAdapter#isIncluded(org.eclipse.emf.ecore.EReference)
+ */
+ @Override
+ protected boolean isIncluded(EReference eReference) {
+ return eReference == TreePackage.Literals.TREE_NODE__DATA;
+ }
+ };
+ final ConflictsGroupImpl conflictsGroup = new ConflictsGroupImpl(comparison,
+ hasConflict(ConflictKind.REAL, ConflictKind.PSEUDO),
+ EMFCompareRCPUIMessages.getString("ThreeWayComparisonGroupProvider.conflicts.label"), //$NON-NLS-1$
+ crossReferenceAdapter);
+ conflictsGroup.buildSubTree();
+
+ // There is one conflict node
+ List<? extends TreeNode> conflictNodes = conflictsGroup.getChildren();
+ assertEquals(1, conflictNodes.size());
+
+ // The conflict node groups two conflicts
+ ConflictNode conflictNode = (ConflictNode)conflictNodes.get(0);
+ Conflict conflict = conflictNode.getConflict();
+ assertTrue(conflict instanceof CompositeConflict);
+ CompositeConflict compositeConflict = (CompositeConflict)conflict;
+ assertEquals(2, compositeConflict.getConflicts().size());
+
+ List<? extends TreeNode> matchNodes = conflictNode.getChildren();
+ assertEquals(2, matchNodes.size());
+
+ // Match node for association
+ MatchNode matchNodeAssociation = (MatchNode)matchNodes.get(0);
+ checkText(matchNodeAssociation, "Association"); //$NON-NLS-1$
+
+ // Match node for association property owned by class1
+ MatchNode matchNodePropertyClass1 = (MatchNode)matchNodes.get(1);
+ checkText(matchNodePropertyClass1, "Property class2_"); //$NON-NLS-1$
+
+ List<? extends TreeNode> childrenMatchNodeAssociation = matchNodeAssociation.getChildren();
+ assertEquals(2, childrenMatchNodeAssociation.size());
+
+ // Diff node for deletion of association
+ DiffNode diffNodeDeletion = (DiffNode)childrenMatchNodeAssociation.get(0);
+ checkText(diffNodeDeletion, "Association Change DELETE"); //$NON-NLS-1$
+ assertTrue(diffNodeDeletion.getChildren().size() > 0);
+
+ // Match node for association property owned by association
+ MatchNode matchNodePropertyAssociation = (MatchNode)childrenMatchNodeAssociation.get(1);
+ checkText(matchNodePropertyAssociation, "Property class1_"); //$NON-NLS-1$
+ List<? extends TreeNode> childrenMatchNodePropertyAssociation = matchNodePropertyAssociation
+ .getChildren();
+ assertEquals(1, childrenMatchNodePropertyAssociation.size());
+
+ // Diff node for name update of association property owned by association
+ DiffNode diffNodeUpdatePropertyAssociation = (DiffNode)childrenMatchNodePropertyAssociation.get(0);
+ checkText(diffNodeUpdatePropertyAssociation, "class1_ [name set]"); //$NON-NLS-1$
+ assertEquals(0, diffNodeUpdatePropertyAssociation.getChildren().size());
+
+ List<? extends TreeNode> childrenMatchNodePropertyClass1 = matchNodePropertyClass1.getChildren();
+ assertEquals(1, childrenMatchNodePropertyClass1.size());
+
+ // Diff node for name update of association property owned by class1
+ DiffNode diffNodeUpdatePropertyClass1 = (DiffNode)childrenMatchNodePropertyClass1.get(0);
+ checkText(diffNodeUpdatePropertyClass1, "class2_ [name set]"); //$NON-NLS-1$
+ assertEquals(0, diffNodeUpdatePropertyClass1.getChildren().size());
+ }
+
+ protected void checkText(TreeNode childNode, String expected) {
+ assertEquals(expected, itemDelegator.getText(childNode));
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/UMLJoiningConflictsWithOverlappingDiffsInputData.java b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/UMLJoiningConflictsWithOverlappingDiffsInputData.java
new file mode 100644
index 000000000..787dca21b
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/UMLJoiningConflictsWithOverlappingDiffsInputData.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Services GmbH and others.
+ * 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:
+ * Tanja Mayerhofer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.rcp.ui.tests.groups.data.uml.compositeconflict;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.tests.edit.data.ResourceScopeProvider;
+import org.eclipse.emf.compare.tests.framework.AbstractInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+
+public class UMLJoiningConflictsWithOverlappingDiffsInputData extends AbstractInputData implements ResourceScopeProvider {
+
+ public Resource getLeft() throws IOException {
+ return loadFromClassLoader("left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getRight() throws IOException {
+ return loadFromClassLoader("right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getOrigin() throws IOException {
+ return loadFromClassLoader("origin.uml"); //$NON-NLS-1$
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/left.uml b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/left.uml
new file mode 100644
index 000000000..a189e5262
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/left.uml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_gPPNkH_3EeaBipewnLNB5Q" name="model">
+ <packagedElement xmi:type="uml:Class" xmi:id="_hjK6oH_3EeaBipewnLNB5Q" name="Class1">
+ <ownedAttribute xmi:type="uml:Property" xmi:id="_RgcocH_4EeaBipewnLNB5Q" name="class2_" type="_iTQTwH_3EeaBipewnLNB5Q" association="_RgaMMH_4EeaBipewnLNB5Q"/>
+ </packagedElement>
+ <packagedElement xmi:type="uml:Class" xmi:id="_iTQTwH_3EeaBipewnLNB5Q" name="Class2"/>
+ <packagedElement xmi:type="uml:Association" xmi:id="_RgaMMH_4EeaBipewnLNB5Q" memberEnd="_RgcocH_4EeaBipewnLNB5Q _RgcocX_4EeaBipewnLNB5Q">
+ <eAnnotations xmi:type="ecore:EAnnotation" xmi:id="_RgcBYH_4EeaBipewnLNB5Q" source="org.eclipse.papyrus">
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_RgcBYX_4EeaBipewnLNB5Q" key="nature" value="UML_Nature"/>
+ </eAnnotations>
+ <ownedEnd xmi:type="uml:Property" xmi:id="_RgcocX_4EeaBipewnLNB5Q" name="class1_" type="_hjK6oH_3EeaBipewnLNB5Q" association="_RgaMMH_4EeaBipewnLNB5Q"/>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/origin.uml b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/origin.uml
new file mode 100644
index 000000000..4d7c8be8e
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/origin.uml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_gPPNkH_3EeaBipewnLNB5Q" name="model">
+ <packagedElement xmi:type="uml:Class" xmi:id="_hjK6oH_3EeaBipewnLNB5Q" name="Class1">
+ <ownedAttribute xmi:type="uml:Property" xmi:id="_RgcocH_4EeaBipewnLNB5Q" name="class2" type="_iTQTwH_3EeaBipewnLNB5Q" association="_RgaMMH_4EeaBipewnLNB5Q"/>
+ </packagedElement>
+ <packagedElement xmi:type="uml:Class" xmi:id="_iTQTwH_3EeaBipewnLNB5Q" name="Class2"/>
+ <packagedElement xmi:type="uml:Association" xmi:id="_RgaMMH_4EeaBipewnLNB5Q" memberEnd="_RgcocH_4EeaBipewnLNB5Q _RgcocX_4EeaBipewnLNB5Q">
+ <eAnnotations xmi:type="ecore:EAnnotation" xmi:id="_RgcBYH_4EeaBipewnLNB5Q" source="org.eclipse.papyrus">
+ <details xmi:type="ecore:EStringToStringMapEntry" xmi:id="_RgcBYX_4EeaBipewnLNB5Q" key="nature" value="UML_Nature"/>
+ </eAnnotations>
+ <ownedEnd xmi:type="uml:Property" xmi:id="_RgcocX_4EeaBipewnLNB5Q" name="class1" type="_hjK6oH_3EeaBipewnLNB5Q" association="_RgaMMH_4EeaBipewnLNB5Q"/>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/right.uml b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/right.uml
new file mode 100644
index 000000000..dca1cd5fe
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/compositeconflict/right.uml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_gPPNkH_3EeaBipewnLNB5Q" name="model">
+ <packagedElement xmi:type="uml:Class" xmi:id="_hjK6oH_3EeaBipewnLNB5Q" name="Class1"/>
+ <packagedElement xmi:type="uml:Class" xmi:id="_iTQTwH_3EeaBipewnLNB5Q" name="Class2"/>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/UMLConflictWithRefiningDiffInputData.java b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/UMLConflictWithRefiningDiffInputData.java
new file mode 100644
index 000000000..b807fd7e7
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/UMLConflictWithRefiningDiffInputData.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EclipseSource Services GmbH and others.
+ * 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:
+ * Tanja Mayerhofer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.rcp.ui.tests.groups.data.uml.conflictrefiningdiffs;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.tests.edit.data.ResourceScopeProvider;
+import org.eclipse.emf.compare.tests.framework.AbstractInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+
+public class UMLConflictWithRefiningDiffInputData extends AbstractInputData implements ResourceScopeProvider {
+
+ public Resource getLeft() throws IOException {
+ return loadFromClassLoader("left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getRight() throws IOException {
+ return loadFromClassLoader("right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getOrigin() throws IOException {
+ return loadFromClassLoader("origin.uml"); //$NON-NLS-1$
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/left.uml b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/left.uml
new file mode 100644
index 000000000..3cd1a0067
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/left.uml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_lVcg8H_MEeayp7MnooaiIA" name="model">
+ <packagedElement xmi:type="uml:Activity" xmi:id="_lVsYkH_MEeayp7MnooaiIA" name="Activity1" node="_sI5KsH_MEeayp7MnooaiIA">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_sI5KsH_MEeayp7MnooaiIA" name="OpaqueAction">
+ <language>Natural language</language>
+ <body>This is a natural language definition of OpaqueAction.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/origin.uml b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/origin.uml
new file mode 100644
index 000000000..5ecbfa50e
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/origin.uml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_lVcg8H_MEeayp7MnooaiIA" name="model">
+ <packagedElement xmi:type="uml:Activity" xmi:id="_lVsYkH_MEeayp7MnooaiIA" name="Activity1" node="_sI5KsH_MEeayp7MnooaiIA">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_sI5KsH_MEeayp7MnooaiIA" name="OpaqueAction"/>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/right.uml b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/right.uml
new file mode 100644
index 000000000..9c784e1a8
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/groups/data/uml/conflictrefiningdiffs/right.uml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_lVcg8H_MEeayp7MnooaiIA" name="model">
+ <packagedElement xmi:type="uml:Activity" xmi:id="_lVsYkH_MEeayp7MnooaiIA" name="Activity1"/>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/suite/AllTests.java b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/suite/AllTests.java
index b6335d66e..e154b0a14 100644
--- a/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/suite/AllTests.java
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui.tests/src/org/eclipse/emf/compare/uml2/rcp/ui/tests/suite/AllTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014 Obeo.
+ * Copyright (c) 2014, 2106 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
@@ -7,13 +7,11 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Tanja Mayerhofer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.uml2.rcp.ui.tests.suite;
-import junit.framework.JUnit4TestAdapter;
-import junit.framework.Test;
-import junit.textui.TestRunner;
-
+import org.eclipse.emf.compare.uml2.rcp.ui.tests.groups.ConflictsGroupTest;
import org.eclipse.emf.compare.uml2.rcp.ui.tests.groups.UMLDifferencesOrderTest;
import org.eclipse.emf.compare.uml2.rcp.ui.tests.profile.DynamicProfileIntegrationDisplayTest;
import org.eclipse.emf.compare.uml2.rcp.ui.tests.profile.StaticProfileIntegrationDisplayTest;
@@ -21,6 +19,10 @@ import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.textui.TestRunner;
+
/**
* This test suite allows us to launch all tests for EMF Compare at once.
*
@@ -28,7 +30,7 @@ import org.junit.runners.Suite.SuiteClasses;
*/
@RunWith(Suite.class)
@SuiteClasses({UMLDifferencesOrderTest.class, DynamicProfileIntegrationDisplayTest.class,
- StaticProfileIntegrationDisplayTest.class })
+ StaticProfileIntegrationDisplayTest.class, ConflictsGroupTest.class })
public class AllTests {
/**
diff --git a/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/OpaqueElementBodyChangeAccessor.java b/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/OpaqueElementBodyChangeAccessor.java
index e22c79402..36e38bef9 100644
--- a/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/OpaqueElementBodyChangeAccessor.java
+++ b/plugins/org.eclipse.emf.compare.uml2.rcp.ui/src/org/eclipse/emf/compare/uml2/rcp/ui/internal/accessor/OpaqueElementBodyChangeAccessor.java
@@ -14,6 +14,7 @@ import com.google.common.base.Optional;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
+import java.util.Collections;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
@@ -111,6 +112,9 @@ public class OpaqueElementBodyChangeAccessor extends AbstractTypedElementAdapter
*/
@SuppressWarnings("unchecked")
private List<String> getLanguageValues() {
+ if (eObject == null) {
+ return Collections.emptyList();
+ }
return (List<String>)ReferenceUtil.safeEGet(eObject, getLanguageFeature());
}
@@ -121,6 +125,9 @@ public class OpaqueElementBodyChangeAccessor extends AbstractTypedElementAdapter
*/
@SuppressWarnings("unchecked")
private List<String> getBodyValues() {
+ if (eObject == null) {
+ return Collections.emptyList();
+ }
return (List<String>)ReferenceUtil.safeEGet(eObject, getBodyFeature());
}
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java
index fb2d3f0dc..78388134c 100644
--- a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2012, 2015 Obeo and others.
+ * Copyright (c) 2012, 2016 Obeo and others.
* 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
@@ -8,13 +8,14 @@
* Contributors:
* Obeo - initial API and implementation
* Stefan Dirix - update priority value for UML merger
+ * Philip Langer - bug 501864
*/
package org.eclipse.emf.compare.uml2.tests;
import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Iterators.all;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasConflict;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasDirectOrIndirectConflict;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -70,7 +71,7 @@ import org.junit.Before;
/**
* @author <a href="mailto:cedric.notot@obeo.fr">Cedric Notot</a>
*/
-@SuppressWarnings("nls")
+@SuppressWarnings({"nls", "restriction" })
public abstract class AbstractUMLTest {
protected EMFCompare emfCompare;
@@ -253,7 +254,7 @@ public abstract class AbstractUMLTest {
EList<Diff> differencesAfter = comparisonAfter.getDifferences();
final boolean diffs;
if (pseudoAllowed) {
- diffs = all(differencesAfter.iterator(), hasConflict(ConflictKind.PSEUDO));
+ diffs = all(differencesAfter.iterator(), hasDirectOrIndirectConflict(ConflictKind.PSEUDO));
} else {
diffs = differencesAfter.isEmpty();
}
@@ -271,7 +272,7 @@ public abstract class AbstractUMLTest {
EList<Diff> differencesAfter = comparisonAfter.getDifferences();
final boolean diffs;
if (pseudoAllowed) {
- diffs = all(differencesAfter.iterator(), hasConflict(ConflictKind.PSEUDO));
+ diffs = all(differencesAfter.iterator(), hasDirectOrIndirectConflict(ConflictKind.PSEUDO));
} else {
diffs = differencesAfter.isEmpty();
}
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/multiplicitychanges/MultiplicityElementChangesTest.java b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/multiplicitychanges/MultiplicityElementChangesTest.java
index ebc18cdba..292ba9761 100644
--- a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/multiplicitychanges/MultiplicityElementChangesTest.java
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/multiplicitychanges/MultiplicityElementChangesTest.java
@@ -7,15 +7,18 @@
*
* Contributors:
* Alexandra Buzila - initial API and implementation
+ * Philip Langer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.uml2.tests.multiplicitychanges;
import static com.google.common.base.Predicates.and;
import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.size;
import static org.eclipse.emf.compare.DifferenceSource.LEFT;
import static org.eclipse.emf.compare.DifferenceSource.RIGHT;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -133,12 +136,12 @@ public class MultiplicityElementChangesTest {
MultiplicityElementChange leftChange = (MultiplicityElementChange)leftChanges.iterator().next();
assertEquals(1, leftChange.getRefinedBy().size());
- assertTrue(leftChange.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(leftChange) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, leftChange.getKind());
MultiplicityElementChange rightChange = (MultiplicityElementChange)rightChanges.iterator().next();
assertEquals(1, rightChange.getRefinedBy().size());
- assertTrue(rightChange.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, rightChange.getKind());
assertEquals(0, comparison.getConflicts().size());
@@ -163,29 +166,29 @@ public class MultiplicityElementChangesTest {
MultiplicityElementChange leftChange = (MultiplicityElementChange)leftChanges.get(0);
assertEquals(1, leftChange.getRefinedBy().size());
- assertTrue(leftChange.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(leftChange) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, leftChange.getKind());
MultiplicityElementChange rightChange1 = (MultiplicityElementChange)rightChanges.get(0);
assertEquals(1, rightChange1.getRefinedBy().size());
- assertTrue(rightChange1.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange1) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, rightChange1.getKind());
MultiplicityElementChange rightChange2 = (MultiplicityElementChange)rightChanges.get(1);
assertEquals(1, rightChange2.getRefinedBy().size());
- assertTrue(rightChange2.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange2) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, rightChange2.getKind());
assertEquals(1, comparison.getConflicts().size());
Conflict conflict = comparison.getConflicts().get(0);
assertEquals(ConflictKind.PSEUDO, conflict.getKind());
- assertTrue(conflict.getDifferences().contains(leftChange));
+ assertTrue(conflict.getDifferences().contains(getFirstRefiningDiff(leftChange)));
if (isLowerValueChange(rightChange1)) {
- assertEquals(conflict, rightChange1.getConflict());
+ assertEquals(conflict, getRefiningsConflict(rightChange1));
} else {
assertTrue(isLowerValueChange(rightChange2));
- assertEquals(conflict, rightChange2.getConflict());
+ assertEquals(conflict, getRefiningsConflict(rightChange2));
}
}
@@ -208,17 +211,17 @@ public class MultiplicityElementChangesTest {
MultiplicityElementChange leftChange = (MultiplicityElementChange)leftChanges.get(0);
assertEquals(1, leftChange.getRefinedBy().size());
- assertTrue(leftChange.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(leftChange) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, leftChange.getKind());
MultiplicityElementChange rightChange1 = (MultiplicityElementChange)rightChanges.get(0);
assertEquals(1, rightChange1.getRefinedBy().size());
- assertTrue(rightChange1.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange1) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, rightChange1.getKind());
MultiplicityElementChange rightChange2 = (MultiplicityElementChange)rightChanges.get(1);
assertEquals(1, rightChange2.getRefinedBy().size());
- assertTrue(rightChange2.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange2) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, rightChange2.getKind());
assertEquals(1, comparison.getConflicts().size());
@@ -226,10 +229,10 @@ public class MultiplicityElementChangesTest {
assertEquals(ConflictKind.REAL, conflict.getKind());
if (isLowerValueChange(rightChange1)) {
- assertEquals(conflict, rightChange1.getConflict());
+ assertEquals(conflict, getRefiningsConflict(rightChange1));
} else {
assertTrue(isLowerValueChange(rightChange2));
- assertEquals(conflict, rightChange2.getConflict());
+ assertEquals(conflict, getRefiningsConflict(rightChange2));
}
}
@@ -248,19 +251,19 @@ public class MultiplicityElementChangesTest {
assertEquals(1, size(leftChanges));
MultiplicityElementChange leftChange = (MultiplicityElementChange)leftChanges.iterator().next();
assertEquals(1, leftChange.getRefinedBy().size());
- assertTrue(leftChange.getRefinedBy().get(0) instanceof AttributeChange);
+ assertTrue(getFirstRefiningDiff(leftChange) instanceof AttributeChange);
assertEquals(DifferenceKind.CHANGE, leftChange.getKind());
assertEquals(1, size(rightChanges));
MultiplicityElementChange rightChange = (MultiplicityElementChange)rightChanges.iterator().next();
assertEquals(1, rightChange.getRefinedBy().size());
- assertTrue(rightChange.getRefinedBy().get(0) instanceof AttributeChange);
+ assertTrue(getFirstRefiningDiff(rightChange) instanceof AttributeChange);
assertEquals(DifferenceKind.CHANGE, rightChange.getKind());
assertEquals(1, comparison.getConflicts().size());
Conflict conflict = comparison.getConflicts().get(0);
assertEquals(ConflictKind.REAL, conflict.getKind());
- assertEquals(conflict, rightChange.getConflict());
+ assertEquals(conflict, getRefiningsConflict(rightChange));
}
/**
@@ -290,7 +293,7 @@ public class MultiplicityElementChangesTest {
assertEquals(1, comparison.getConflicts().size());
Conflict conflict = comparison.getConflicts().get(0);
assertEquals(ConflictKind.PSEUDO, conflict.getKind());
- assertEquals(conflict, rightChange.getConflict());
+ assertEquals(conflict, getRefiningsConflict(rightChange));
}
@@ -310,19 +313,19 @@ public class MultiplicityElementChangesTest {
assertEquals(1, size(leftChanges));
MultiplicityElementChange leftChange = (MultiplicityElementChange)leftChanges.iterator().next();
assertEquals(1, leftChange.getRefinedBy().size());
- assertTrue(leftChange.getRefinedBy().get(0) instanceof AttributeChange);
+ assertTrue(getFirstRefiningDiff(leftChange) instanceof AttributeChange);
assertEquals(DifferenceKind.CHANGE, leftChange.getKind());
assertEquals(2, size(rightChanges));
MultiplicityElementChange rightChange1 = (MultiplicityElementChange)rightChanges.get(0);
assertEquals(1, rightChange1.getRefinedBy().size());
- assertTrue(rightChange1.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange1) instanceof ReferenceChange);
assertEquals(DifferenceKind.DELETE, rightChange1.getKind());
MultiplicityElementChange rightChange2 = (MultiplicityElementChange)rightChanges.get(1);
assertEquals(1, rightChange2.getRefinedBy().size());
- assertTrue(rightChange2.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange2) instanceof ReferenceChange);
assertEquals(DifferenceKind.DELETE, rightChange2.getKind());
assertEquals(1, comparison.getConflicts().size());
@@ -331,11 +334,11 @@ public class MultiplicityElementChangesTest {
if (isLowerValueChange(rightChange1)) {
assertTrue(isUpperValueChange(rightChange2));
- assertEquals(conflict, rightChange1.getConflict());
+ assertEquals(conflict, getRefiningsConflict(rightChange1));
} else {
assertTrue(isUpperValueChange(rightChange1));
assertTrue(isLowerValueChange(rightChange2));
- assertEquals(conflict, rightChange2.getConflict());
+ assertEquals(conflict, getRefiningsConflict(rightChange2));
}
}
@@ -353,13 +356,13 @@ public class MultiplicityElementChangesTest {
assertEquals(1, size(leftChanges));
MultiplicityElementChange leftChange = (MultiplicityElementChange)leftChanges.iterator().next();
assertEquals(1, leftChange.getRefinedBy().size());
- assertTrue(leftChange.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(leftChange) instanceof ReferenceChange);
assertEquals(DifferenceKind.DELETE, leftChange.getKind());
assertEquals(1, size(rightChanges));
MultiplicityElementChange rightChange = (MultiplicityElementChange)rightChanges.iterator().next();
assertEquals(1, rightChange.getRefinedBy().size());
- assertTrue(rightChange.getRefinedBy().get(0) instanceof AttributeChange);
+ assertTrue(getFirstRefiningDiff(rightChange) instanceof AttributeChange);
assertEquals(DifferenceKind.CHANGE, rightChange.getKind());
assertEquals(0, comparison.getConflicts().size());
@@ -382,12 +385,12 @@ public class MultiplicityElementChangesTest {
MultiplicityElementChange leftChange = (MultiplicityElementChange)leftChanges.iterator().next();
assertEquals(1, leftChange.getRefinedBy().size());
- assertTrue(leftChange.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(leftChange) instanceof ReferenceChange);
assertEquals(DifferenceKind.DELETE, leftChange.getKind());
MultiplicityElementChange rightChange = (MultiplicityElementChange)rightChanges.iterator().next();
assertEquals(1, rightChange.getRefinedBy().size());
- assertTrue(rightChange.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange) instanceof ReferenceChange);
assertEquals(DifferenceKind.DELETE, rightChange.getKind());
assertEquals(1, comparison.getConflicts().size());
@@ -412,12 +415,12 @@ public class MultiplicityElementChangesTest {
MultiplicityElementChange leftChange = (MultiplicityElementChange)leftChanges.iterator().next();
assertEquals(1, leftChange.getRefinedBy().size());
- assertTrue(leftChange.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(leftChange) instanceof ReferenceChange);
assertEquals(DifferenceKind.DELETE, leftChange.getKind());
MultiplicityElementChange rightChange = (MultiplicityElementChange)rightChanges.iterator().next();
assertEquals(1, rightChange.getRefinedBy().size());
- assertTrue(rightChange.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, rightChange.getKind());
assertEquals(0, comparison.getConflicts().size());
@@ -442,22 +445,22 @@ public class MultiplicityElementChangesTest {
MultiplicityElementChange leftChange1 = (MultiplicityElementChange)leftChanges.get(0);
assertEquals(1, leftChange1.getRefinedBy().size());
- assertTrue(leftChange1.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(leftChange1) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, leftChange1.getKind());
MultiplicityElementChange leftChange2 = (MultiplicityElementChange)leftChanges.get(1);
assertEquals(1, leftChange2.getRefinedBy().size());
- assertTrue(leftChange2.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(leftChange2) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, leftChange2.getKind());
MultiplicityElementChange rightChange1 = (MultiplicityElementChange)rightChanges.get(0);
assertEquals(1, rightChange1.getRefinedBy().size());
- assertTrue(rightChange1.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange1) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, rightChange1.getKind());
MultiplicityElementChange rightChange2 = (MultiplicityElementChange)rightChanges.get(1);
assertEquals(1, rightChange2.getRefinedBy().size());
- assertTrue(rightChange2.getRefinedBy().get(0) instanceof ReferenceChange);
+ assertTrue(getFirstRefiningDiff(rightChange2) instanceof ReferenceChange);
assertEquals(DifferenceKind.ADD, rightChange2.getKind());
assertEquals(2, comparison.getConflicts().size());
@@ -479,25 +482,25 @@ public class MultiplicityElementChangesTest {
} else {
assertTrue(isLowerValueChange(leftChange1));
assertTrue(isUpperValueChange(leftChange2));
- assertNotNull(leftChange1.getConflict());
- assertEquals(ConflictKind.PSEUDO, leftChange1.getConflict().getKind());
- assertNotNull(leftChange2.getConflict());
- assertEquals(ConflictKind.REAL, leftChange2.getConflict().getKind());
+ assertNotNull(getRefiningsConflict(leftChange1));
+ assertEquals(ConflictKind.PSEUDO, getRefiningsConflict(leftChange1).getKind());
+ assertNotNull(getRefiningsConflict(leftChange2));
+ assertEquals(ConflictKind.REAL, getRefiningsConflict(leftChange2).getKind());
}
if (isUpperValueChange(rightChange1)) {
assertTrue(isLowerValueChange(rightChange2));
- assertNotNull(rightChange1.getConflict());
- assertEquals(ConflictKind.REAL, rightChange1.getConflict().getKind());
- assertNotNull(rightChange2.getConflict());
- assertEquals(ConflictKind.PSEUDO, rightChange2.getConflict().getKind());
+ assertNotNull(getRefiningsConflict(rightChange1));
+ assertEquals(ConflictKind.REAL, getRefiningsConflict(rightChange1).getKind());
+ assertNotNull(getRefiningsConflict(rightChange2));
+ assertEquals(ConflictKind.PSEUDO, getRefiningsConflict(rightChange2).getKind());
} else {
assertTrue(isLowerValueChange(rightChange1));
assertTrue(isUpperValueChange(rightChange2));
- assertNotNull(rightChange1.getConflict());
- assertEquals(ConflictKind.PSEUDO, rightChange1.getConflict().getKind());
- assertNotNull(rightChange2.getConflict());
- assertEquals(ConflictKind.REAL, rightChange2.getConflict().getKind());
+ assertNotNull(getRefiningsConflict(rightChange1));
+ assertEquals(ConflictKind.PSEUDO, getRefiningsConflict(rightChange1).getKind());
+ assertNotNull(getRefiningsConflict(rightChange2));
+ assertEquals(ConflictKind.REAL, getRefiningsConflict(rightChange2).getKind());
}
}
@@ -506,14 +509,14 @@ public class MultiplicityElementChangesTest {
if (multiplicityElementChange.getRefinedBy().size() != 1) {
return false;
}
- return IS_LOWER_VALUE_CHANGE.apply(multiplicityElementChange.getRefinedBy().get(0));
+ return IS_LOWER_VALUE_CHANGE.apply(getFirstRefiningDiff(multiplicityElementChange));
}
private boolean isUpperValueChange(MultiplicityElementChange multiplicityElementChange) {
if (multiplicityElementChange.getRefinedBy().size() != 1) {
return false;
}
- return IS_UPPER_VALUE_CHANGE.apply(multiplicityElementChange.getRefinedBy().get(0));
+ return IS_UPPER_VALUE_CHANGE.apply(getFirstRefiningDiff(multiplicityElementChange));
}
/**
@@ -534,43 +537,27 @@ public class MultiplicityElementChangesTest {
assertEquals(2, size(leftChanges));
assertEquals(2, size(rightChanges));
- MultiplicityElementChange leftAddChange;
- MultiplicityElementChange leftDeleteChange;
-
- if (leftChanges.get(0).getKind() == DifferenceKind.ADD) {
- leftAddChange = (MultiplicityElementChange)leftChanges.get(0);
- leftDeleteChange = (MultiplicityElementChange)leftChanges.get(1);
- } else {
- leftAddChange = (MultiplicityElementChange)leftChanges.get(1);
- leftDeleteChange = (MultiplicityElementChange)leftChanges.get(0);
- }
+ MultiplicityElementChange leftAddChange = (MultiplicityElementChange)find(leftChanges,
+ ofKind(DifferenceKind.ADD));
+ MultiplicityElementChange leftDeleteChange = (MultiplicityElementChange)find(leftChanges,
+ ofKind(DifferenceKind.DELETE));
assertEquals(1, leftAddChange.getRefinedBy().size());
- assertTrue(leftAddChange.getRefinedBy().get(0) instanceof ReferenceChange);
- assertEquals(DifferenceKind.ADD, leftAddChange.getKind());
+ assertTrue(getFirstRefiningDiff(leftAddChange) instanceof ReferenceChange);
assertEquals(1, leftDeleteChange.getRefinedBy().size());
- assertTrue(leftDeleteChange.getRefinedBy().get(0) instanceof ReferenceChange);
- assertEquals(DifferenceKind.DELETE, leftDeleteChange.getKind());
+ assertTrue(getFirstRefiningDiff(leftDeleteChange) instanceof ReferenceChange);
- MultiplicityElementChange rightChange;
- MultiplicityElementChange rightAddChange;
-
- if (rightChanges.get(0).getKind() == DifferenceKind.ADD) {
- rightAddChange = (MultiplicityElementChange)rightChanges.get(0);
- rightChange = (MultiplicityElementChange)rightChanges.get(1);
- } else {
- rightAddChange = (MultiplicityElementChange)rightChanges.get(1);
- rightChange = (MultiplicityElementChange)rightChanges.get(0);
- }
+ MultiplicityElementChange rightAddChange = (MultiplicityElementChange)find(leftChanges,
+ ofKind(DifferenceKind.ADD));
+ MultiplicityElementChange rightChange = (MultiplicityElementChange)find(rightChanges,
+ ofKind(DifferenceKind.CHANGE));
assertEquals(1, rightAddChange.getRefinedBy().size());
- assertTrue(rightAddChange.getRefinedBy().get(0) instanceof ReferenceChange);
- assertEquals(DifferenceKind.ADD, rightAddChange.getKind());
+ assertTrue(getFirstRefiningDiff(rightAddChange) instanceof ReferenceChange);
assertEquals(1, rightChange.getRefinedBy().size());
- assertTrue(rightChange.getRefinedBy().get(0) instanceof AttributeChange);
- assertEquals(DifferenceKind.CHANGE, rightChange.getKind());
+ assertTrue(getFirstRefiningDiff(rightChange) instanceof AttributeChange);
assertEquals(2, comparison.getConflicts().size());
Conflict conflict1 = comparison.getConflicts().get(0);
@@ -581,20 +568,43 @@ public class MultiplicityElementChangesTest {
} else {
assertEquals(ConflictKind.PSEUDO, conflict2.getKind());
}
- assertEquals(ConflictKind.REAL, leftDeleteChange.getConflict().getKind());
- assertEquals(leftDeleteChange.getConflict(), rightChange.getConflict());
- assertEquals(ConflictKind.PSEUDO, leftAddChange.getConflict().getKind());
- assertEquals(leftAddChange.getConflict(), rightAddChange.getConflict());
+ final Conflict leftChangeConflict = getRefiningsConflict(leftDeleteChange);
+ final Conflict rightChangeConflict = getRefiningsConflict(rightChange);
+ final Conflict leftAddConflict = getRefiningsConflict(leftAddChange);
+ final Conflict rightAddConflict = getRefiningsConflict(rightAddChange);
+ assertEquals(ConflictKind.REAL, leftChangeConflict.getKind());
+ assertEquals(leftChangeConflict, rightChangeConflict);
+ assertEquals(ConflictKind.PSEUDO, leftAddConflict.getKind());
+ assertEquals(leftAddConflict, rightAddConflict);
+ }
+
+ /**
+ * Returns the first refining diff.
+ * <p>
+ * In the context of MultiplicityElementChanges, this is the prime refining, i.e., the attribute or
+ * reference change that essentially performs the multiplicity change.
+ * </p>
+ *
+ * @param change
+ * The multiplicity change.
+ * @return The first refining diff.
+ */
+ private Diff getFirstRefiningDiff(Diff change) {
+ return change.getRefinedBy().get(0);
}
- // @Override
- // protected void registerPostProcessors(
- // org.eclipse.emf.compare.postprocessor.IPostProcessor.Descriptor.Registry<String> postProcessorRegistry)
- // {
- // super.registerPostProcessors(postProcessorRegistry);
- // postProcessorRegistry.put(MultiplicityElementChangePostProcessor.class.getName(),
- // new TestPostProcessor.TestPostProcessorDescriptor(Pattern
- // .compile("http://www.eclipse.org/uml2/\\d\\.0\\.0/UML"), null, //$NON-NLS-1$
- // new MultiplicityElementChangePostProcessor(), 25));
- // }
+ /**
+ * Returns the conflict of the {@link #getFirstRefiningDiff(Diff) first refining diff}.
+ * <p>
+ * In the context of MultiplicityElementChanges, this is the conflict in which the
+ * MultiplicityElementChanges is involved.
+ * </p>
+ *
+ * @param change
+ * The multiplicity change.
+ * @return The conflict of the multiplicity change.
+ */
+ private Conflict getRefiningsConflict(Diff change) {
+ return getFirstRefiningDiff(change).getConflict();
+ }
}
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/stereotypes/AbstractStereotypedElementChangeTests.java b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/stereotypes/AbstractStereotypedElementChangeTests.java
index a952dbd0e..f0647fb82 100644
--- a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/stereotypes/AbstractStereotypedElementChangeTests.java
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/stereotypes/AbstractStereotypedElementChangeTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014 Obeo.
+ * Copyright (c) 2014, 2016 Obeo and others.
* 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
@@ -7,6 +7,7 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Philip Langer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.uml2.tests.stereotypes;
@@ -17,11 +18,14 @@ import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.removed;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.Iterables;
import java.io.IOException;
@@ -886,16 +890,22 @@ public abstract class AbstractStereotypedElementChangeTests extends AbstractUMLP
final ReferenceChange baseDiff = assertDeletedBaseElementDiff(differences, "model.Class0", //$NON-NLS-1$
stereotypedElementChange);
- final Conflict conflict = stereotypedElementChange.getConflict();
+ // the stereotype change itself is not in a conflict
+ assertNull(stereotypedElementChange.getConflict());
+
+ // but one of its refining diffs is in exactly one conflict
+ final Set<Conflict> conflicts = getConflictsOfRefiningDiffs(stereotypedElementChange);
+ final Conflict conflict = Iterables.getOnlyElement(conflicts);
+
assertNotNull(conflict);
- assertEquals(3, conflict.getDifferences().size());
+ assertEquals(2, conflict.getDifferences().size());
final EList<Diff> leftDifferences = conflict.getLeftDifferences();
assertEquals(1, leftDifferences.size());
final Diff leftDiff = leftDifferences.get(0);
assertTrue(leftDiff instanceof AttributeChange);
- assertEquals(2, conflict.getRightDifferences().size());
+ assertEquals(1, conflict.getRightDifferences().size());
assertTrue(conflict.getRightDifferences().contains(baseDiff));
// Merges
@@ -974,9 +984,13 @@ public abstract class AbstractStereotypedElementChangeTests extends AbstractUMLP
final ReferenceChange baseDiff = assertDeletedBaseElementDiff(differences, "model.Class0", //$NON-NLS-1$
stereotypedElementChange);
- final Conflict conflict = stereotypedElementChange.getConflict();
- assertNotNull(conflict);
- assertEquals(3, conflict.getDifferences().size());
+ // the stereotype change itself is not in a conflict
+ assertNull(stereotypedElementChange.getConflict());
+
+ // but one of its refining diffs is in exactly one conflict
+ final Set<Conflict> conflicts = getConflictsOfRefiningDiffs(stereotypedElementChange);
+ final Conflict conflict = Iterables.getOnlyElement(conflicts);
+ assertEquals(2, conflict.getDifferences().size());
final EList<Diff> leftDifferences = conflict.getLeftDifferences();
assertEquals(1, leftDifferences.size());
@@ -984,7 +998,7 @@ public abstract class AbstractStereotypedElementChangeTests extends AbstractUMLP
final Diff leftConflictDiff = leftDifferences.get(0);
assertTrue(leftConflictDiff instanceof AttributeChange);
- assertEquals(2, conflict.getRightDifferences().size());
+ assertEquals(1, conflict.getRightDifferences().size());
assertTrue(conflict.getRightDifferences().contains(baseDiff));
// Merges
mergeLeftToRight(stereotypedElementChange);
@@ -1006,6 +1020,23 @@ public abstract class AbstractStereotypedElementChangeTests extends AbstractUMLP
}
/**
+ * Returns the conflicts of the refining diffs of the given {@code refinedDiff}.
+ *
+ * @param refinedDiff
+ * The refined diff to get the conflicts from.
+ * @return the list of conflicts.
+ */
+ private Set<Conflict> getConflictsOfRefiningDiffs(Diff refinedDiff) {
+ Builder<Conflict> builder = ImmutableSet.builder();
+ for (Diff refiningDiff : refinedDiff.getRefinedBy()) {
+ if (refiningDiff.getConflict() != null) {
+ builder.add(refiningDiff.getConflict());
+ }
+ }
+ return builder.build();
+ }
+
+ /**
* Checks that the input has the same structure than described bellow:
* <p>
* <h4>Expected model</h4>
diff --git a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java
index 466ce600b..fc0317205 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/MultiplicityElementChangePostProcessor.java
@@ -7,24 +7,31 @@
*
* Contributors:
* Alexandra Buzila - initial API and implementation
+ * Philip Langer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.uml2.internal.postprocessor;
+import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.collect.Iterables.all;
import static com.google.common.collect.Iterables.filter;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.anyRefined;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import java.util.ArrayList;
import java.util.Iterator;
+import java.util.List;
-import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.Monitor;
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.ReferenceChange;
import org.eclipse.emf.compare.postprocessor.IPostProcessor;
@@ -33,8 +40,6 @@ import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
-import org.eclipse.uml2.uml.MultiplicityElement;
-import org.eclipse.uml2.uml.UMLPackage;
/**
* Post processor handling conflicts of {@link MultiplicityElementChange MultiplicityElementChanges}.
@@ -43,35 +48,6 @@ import org.eclipse.uml2.uml.UMLPackage;
*/
public class MultiplicityElementChangePostProcessor implements IPostProcessor {
- /**
- * A predicate that can be used to check whether a {@link Diff} is a {@link MultiplicityElementChange}.
- */
- private static final Predicate<Diff> IS_MULTIPLICITY_CHANGE = new Predicate<Diff>() {
- public boolean apply(Diff diff) {
- return diff instanceof MultiplicityElementChange;
- }
- };
-
- /**
- * A predicate that can be used to check whether a {@link Diff} is a {@link MultiplicityElementChange} and
- * its {@link DifferenceSource} is LEFT.
- */
- private static final Predicate<Diff> IS_LEFT_MULTIPLICITY_CHANGE = new Predicate<Diff>() {
- public boolean apply(Diff diff) {
- return DifferenceSource.LEFT.equals(diff.getSource()) && IS_MULTIPLICITY_CHANGE.apply(diff);
- }
- };
-
- /**
- * A predicate that can be used to check whether a {@link Diff} is a {@link MultiplicityElementChange} and
- * its {@link DifferenceSource} is RIGHT.
- */
- private static final Predicate<Diff> IS_RIGHT_MULTIPLICITY_CHANGE = new Predicate<Diff>() {
- public boolean apply(Diff diff) {
- return DifferenceSource.RIGHT.equals(diff.getSource()) && IS_MULTIPLICITY_CHANGE.apply(diff);
- }
- };
-
/** {@inheritDoc} */
public void postMatch(Comparison comparison, Monitor monitor) {
// do nothing
@@ -119,7 +95,7 @@ public class MultiplicityElementChangePostProcessor implements IPostProcessor {
*/
private void updateRequiresAndRefines(Comparison comparison) {
Iterator<Diff> multiplicityChanges = Iterators.filter(comparison.getDifferences().iterator(),
- IS_MULTIPLICITY_CHANGE);
+ instanceOf(MultiplicityElementChange.class));
while (multiplicityChanges.hasNext()) {
MultiplicityElementChange refChange = (MultiplicityElementChange)multiplicityChanges.next();
for (Diff refiningDiff : refChange.getRefinedBy()) {
@@ -145,23 +121,41 @@ public class MultiplicityElementChangePostProcessor implements IPostProcessor {
* the comparison containing the conflicts
*/
private void verifyConflicts(Comparison comparison) {
- final EList<Diff> diffs = comparison.getDifferences();
- final Iterable<Diff> leftChanges = filter(diffs, IS_LEFT_MULTIPLICITY_CHANGE);
- for (Diff leftDiff : leftChanges) {
- final MultiplicityElementChange leftChange = (MultiplicityElementChange)leftDiff;
-
- final Match match = leftChange.getMatch();
- final Iterable<Diff> rightChanges = filter(diffs, IS_RIGHT_MULTIPLICITY_CHANGE);
- for (Diff rightDiff : rightChanges) {
- MultiplicityElementChange rightChange = (MultiplicityElementChange)rightDiff;
- if (leftChange.getConflict() != null) {
- verifyConflict(match, leftChange, rightChange);
+ for (Conflict conflict : comparison.getConflicts()) {
+ if (all(conflict.getDifferences(), anyRefined(instanceOf(MultiplicityElementChange.class)))) {
+ final Iterable<Diff> leftDiffs = collectRefinedDiffs(conflict.getLeftDifferences(),
+ instanceOf(MultiplicityElementChange.class));
+ for (Diff leftDiff : leftDiffs) {
+ final MultiplicityElementChange leftMultiplicityChange = (MultiplicityElementChange)leftDiff;
+ final Match match = leftMultiplicityChange.getMatch();
+ final Iterable<Diff> rightDiffs = collectRefinedDiffs(conflict.getRightDifferences(),
+ instanceOf(MultiplicityElementChange.class));
+ for (Diff rightDiff : rightDiffs) {
+ verifyConflict(match, leftMultiplicityChange, (MultiplicityElementChange)rightDiff);
+ }
}
}
}
}
/**
+ * Collects the refined differences that fulfill the given predicate from the given diffs.
+ *
+ * @param diffs
+ * The diffs to collect its refined differences from.
+ * @param predicate
+ * The predicate to be fulfilled.
+ * @return The list of refined differences fulfilling the predicate.
+ */
+ private Iterable<Diff> collectRefinedDiffs(List<Diff> diffs, Predicate<Object> predicate) {
+ Builder<Diff> builder = ImmutableList.builder();
+ for (Diff diff : diffs) {
+ builder.addAll(filter(diff.getRefines(), predicate));
+ }
+ return builder.build();
+ }
+
+ /**
* Verifies whether the {@link ConflictKind} of conflicts between MultiplicityChanges is correct, for a
* given match. Specifically, it checks whether the type of all the diffs refining the multiplicity
* reference changes is correct and makes sure that if a change contains both PSEUDO and REAL conflicts,
@@ -176,101 +170,57 @@ public class MultiplicityElementChangePostProcessor implements IPostProcessor {
*/
private void verifyConflict(Match match, MultiplicityElementChange leftChange,
MultiplicityElementChange rightChange) {
- if (!isRefinedByReferenceChange(leftChange) || !isRefinedByReferenceChange(rightChange)) {
+ final Optional<ReferenceChange> leftReferenceChange = tryGetReferenceChange(leftChange);
+ final Optional<ReferenceChange> rightReferenceChange = tryGetReferenceChange(rightChange);
+ if (!leftReferenceChange.isPresent() || !rightReferenceChange.isPresent()) {
return;
}
- ReferenceChange leftRefChange = (ReferenceChange)leftChange.getRefinedBy().get(0);
- EReference reference = leftRefChange.getReference();
- if (!affectsReference(reference, rightChange)) {
+ final EReference leftReference = leftReferenceChange.get().getReference();
+ final EReference rightReference = rightReferenceChange.get().getReference();
+ if (!leftReference.equals(rightReference)) {
return;
}
- boolean sameValue = sameValue(reference, match.getLeft(), match.getRight());
- updateConflict(leftChange, rightChange, sameValue);
+ final boolean sameValue = sameValue(leftReference, match.getLeft(), match.getRight());
+ updateConflict(leftReferenceChange.get(), rightReferenceChange.get(), sameValue);
}
/**
- * Updates the conflict kind of the given MultiplicityElementChanges.
+ * Updates the conflict kind of the given references that refine MultiplicityElementChanges.
*
- * @param leftChange
+ * @param diff
* the change from the left side
- * @param rightChange
+ * @param diff2
* the change from the right side
* @param sameValue
* specifies whether the conflicting references have the same value (pseudo conflict) or not
* (real conflict)
*/
- private void updateConflict(MultiplicityElementChange leftChange, MultiplicityElementChange rightChange,
- boolean sameValue) {
- if (sameValue && leftChange.getConflict().getKind() != ConflictKind.PSEUDO
- && containsOnlyMultiplicityReferenceChanges(leftChange.getConflict())) {
- leftChange.getConflict().setKind(ConflictKind.PSEUDO);
- } else if (!sameValue && (leftChange.getConflict().getKind() != ConflictKind.REAL
- || rightChange.getConflict().getKind() != ConflictKind.REAL)) {
- Conflict conflict = leftChange.getConflict();
+ private void updateConflict(Diff diff, Diff diff2, boolean sameValue) {
+ if (sameValue && diff.getConflict().getKind() != ConflictKind.PSEUDO) {
+ diff.getConflict().setKind(ConflictKind.PSEUDO);
+ } else if (!sameValue && (diff.getConflict().getKind() != ConflictKind.REAL
+ || diff2.getConflict().getKind() != ConflictKind.REAL)) {
+ Conflict conflict = diff.getConflict();
conflict.setKind(ConflictKind.REAL);
// make sure the multiplicity changes' conflict is the real one
- leftChange.setConflict(conflict);
- rightChange.setConflict(conflict);
- }
-
- }
-
- /**
- * Returns true if the prime refining of the multiplicity element change is a reference change.
- *
- * @param change
- * the {@link MultiplicityElementChange} to check
- * @return whether the given change has a {@link ReferenceChange} as its prime refining
- */
- private boolean isRefinedByReferenceChange(MultiplicityElementChange change) {
- return change.getPrimeRefining() instanceof ReferenceChange;
- }
-
- /**
- * Checks if the given conflict contains differences that are not of type
- * {@link MultiplicityElementChange} or are not {@link ReferenceChange reference changes} of
- * {@link MultiplicityElement multiplicity elements}.
- *
- * @param conflict
- * the conflict to check
- * @return <code>true</code> if the conflict contains only {@link MultiplicityElementChange} diffs
- */
- private boolean containsOnlyMultiplicityReferenceChanges(Conflict conflict) {
- for (Diff diff : conflict.getDifferences()) {
- if (diff instanceof MultiplicityElementChange) {
- continue;
- }
- if (!(diff instanceof ReferenceChange)) {
- return false;
- }
- EReference reference = ((ReferenceChange)diff).getReference();
- if (reference != UMLPackage.eINSTANCE.getMultiplicityElement_LowerValue()
- && reference != UMLPackage.eINSTANCE.getMultiplicityElement_UpperValue()) {
- return false;
- }
+ diff.setConflict(conflict);
+ diff2.setConflict(conflict);
}
- return true;
}
/**
- * Checks whether the given change affects the specified eReference.
+ * Returns the reference change that refines the given multiplicity element change. A multiplicity change
+ * should only have one refining diff, which is a reference change.
*
- * @param eReference
- * the {@link EReference}
* @param change
- * the {@link MultiplicityElementChange}
- * @return true if the given {@link MultiplicityElementChange} contains a refining {@link ReferenceChange}
- * affecting the provided {@link EReference}
+ * The {@link MultiplicityElementChange} to get its refining reference change.
+ * @return The refining reference change.
*/
- private boolean affectsReference(EReference eReference, MultiplicityElementChange change) {
- for (ReferenceChange diff : filter(change.getRefinedBy(), ReferenceChange.class)) {
- if (diff.getReference() == eReference) {
- return true;
- }
- }
- return false;
+ private Optional<ReferenceChange> tryGetReferenceChange(MultiplicityElementChange change) {
+ final Iterable<ReferenceChange> refChanges = filter(change.getRefinedBy(), ReferenceChange.class);
+ return Optional.fromNullable(Iterables.getFirst(refChanges, null));
}
/**
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
index 98ad60f4a..38c2b6293 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
@@ -12,14 +12,11 @@
*******************************************************************************/
package org.eclipse.emf.compare.conflict;
-import static com.google.common.base.Predicates.and;
import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isAddOrSetDiff;
import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isDeleteOrUnsetDiff;
import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isFeatureMapContainment;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueIs;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
@@ -280,7 +277,7 @@ public class DefaultConflictDetector implements IConflictDetector {
} else if (diff.getMatch() == candidate.getMatch()
&& diff.getReference() == candidate.getReference()) {
// Same value added in the same container/reference couple
- if (!diffIsDelete && !candidateIsDelete && matchingIndices(comparison, diff.getMatch(),
+ if (!diffIsDelete && !candidateIsDelete && matchingIndices(diff.getMatch(),
diff.getReference(), diff.getValue(), candidate.getValue())) {
kind = ConflictKind.PSEUDO;
}
@@ -381,9 +378,8 @@ public class DefaultConflictDetector implements IConflictDetector {
} else if (diff.getMatch() == candidate.getMatch()
&& diff.getAttribute() == candidate.getAttribute()) {
// Same value added in the same container/reference couple with the same key
- if (!diffIsDelete
- && !candidateIsDelete && matchingIndices(comparison, diff.getMatch(),
- diff.getAttribute(), diff.getValue(), candidate.getValue())
+ if (!diffIsDelete && !candidateIsDelete && matchingIndices(diff.getMatch(),
+ diff.getAttribute(), diff.getValue(), candidate.getValue())
&& haveSameKey(diff, candidate)) {
kind = ConflictKind.PSEUDO;
}
@@ -673,7 +669,7 @@ public class DefaultConflictDetector implements IConflictDetector {
if (diff.getMatch() == candidate.getMatch()
&& comparison.getEqualityHelper().matchingValues(changedValue, candidateValue)) {
// Same value moved in both side of the same container
- if (matchingIndices(comparison, diff.getMatch(), feature, changedValue, candidateValue)) {
+ if (matchingIndices(diff.getMatch(), feature, changedValue, candidateValue)) {
conflictOn(comparison, diff, candidate, ConflictKind.PSEUDO);
} else {
conflictOn(comparison, diff, candidate, ConflictKind.REAL);
@@ -839,8 +835,7 @@ public class DefaultConflictDetector implements IConflictDetector {
// same value can appear twice.
conflictOn(comparison, diff, candidate, ConflictKind.REAL);
}
- } else if (matchingIndices(comparison, diff.getMatch(), feature, addedValue,
- candidateValue)) {
+ } else if (matchingIndices(diff.getMatch(), feature, addedValue, candidateValue)) {
conflictOn(comparison, diff, candidate, ConflictKind.PSEUDO);
} else {
conflictOn(comparison, diff, candidate, ConflictKind.REAL);
@@ -1044,114 +1039,6 @@ public class DefaultConflictDetector implements IConflictDetector {
}
/**
- * This will be used whenever we check for conflictual MOVEs in order to determine whether we have a
- * pseudo conflict or a real conflict.
- * <p>
- * Namely, this will retrieve the value of the given {@code feature} on the right and left sides of the
- * given {@code match}, then check whether the two given values are on the same index.
- * </p>
- * <p>
- * Note that no sanity checks will be made on either the match's sides or the feature.
- * </p>
- *
- * @param comparison
- * Provides us with the necessary information to match EObjects.
- * @param match
- * Match for which we need to check a feature.
- * @param feature
- * The feature which values we need to check.
- * @param value1
- * First of the two values which index we are to compare.
- * @param value2
- * Second of the two values which index we are to compare.
- * @return {@code true} if the two given values are located at the same index in the given feature's
- * values list, {@code false} otherwise.
- */
- @SuppressWarnings("unchecked")
- private boolean matchingIndices(Comparison comparison, Match match, EStructuralFeature feature,
- Object value1, Object value2) {
- boolean matching = false;
- if (feature.isMany()) {
- final List<Object> leftValues = (List<Object>)ReferenceUtil.safeEGet(match.getLeft(), feature);
- final List<Object> rightValues = (List<Object>)ReferenceUtil.safeEGet(match.getRight(), feature);
-
- // FIXME the detection _will_ fail for non-unique lists with multiple identical values...
- int leftIndex = -1;
- int rightIndex = -1;
- for (int i = 0; i < leftValues.size(); i++) {
- final Object left = leftValues.get(i);
- if (comparison.getEqualityHelper().matchingValues(left, value1)) {
- break;
- } else if (hasDiff(match, feature, left) || hasDeleteDiff(match, feature, left)) {
- // Do not increment.
- } else {
- leftIndex++;
- }
- }
- for (int i = 0; i < rightValues.size(); i++) {
- final Object right = rightValues.get(i);
- if (comparison.getEqualityHelper().matchingValues(right, value2)) {
- break;
- } else if (hasDiff(match, feature, right) || hasDeleteDiff(match, feature, right)) {
- // Do not increment.
- } else {
- rightIndex++;
- }
- }
- matching = leftIndex == rightIndex;
- } else {
- matching = true;
- }
- return matching;
- }
-
- /**
- * Checks whether the given {@code match} presents a difference of any kind on the given {@code feature}'s
- * {@code value}.
- *
- * @param match
- * The match which differences we'll check.
- * @param feature
- * The feature on which we expect a difference.
- * @param value
- * The value we expect to have changed inside {@code feature}.
- * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
- */
- private boolean hasDiff(Match match, EStructuralFeature feature, Object value) {
- return Iterables.any(match.getDifferences(), and(onFeature(feature.getName()), valueIs(value)));
- }
-
- /**
- * Checks whether the given {@code value} has been deleted from the given {@code feature} of {@code match}
- * .
- *
- * @param match
- * The match which differences we'll check.
- * @param feature
- * The feature on which we expect a difference.
- * @param value
- * The value we expect to have been removed from {@code feature}.
- * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
- */
- @SuppressWarnings("unchecked")
- private boolean hasDeleteDiff(Match match, EStructuralFeature feature, Object value) {
- final Comparison comparison = match.getComparison();
- final Object expectedValue;
- if (value instanceof EObject && comparison.isThreeWay()) {
- final Match valueMatch = comparison.getMatch((EObject)value);
- if (valueMatch != null) {
- expectedValue = valueMatch.getOrigin();
- } else {
- expectedValue = value;
- }
- } else {
- expectedValue = value;
- }
- return Iterables.any(match.getDifferences(),
- and(onFeature(feature.getName()), valueIs(expectedValue), ofKind(DifferenceKind.DELETE)));
- }
-
- /**
* This will be called whenever we detect a new conflict in order to create (or update) the actual
* association.
*
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java
index 9eda013a4..4adecb1b2 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AbstractConflictSearch.java
@@ -13,16 +13,10 @@ package org.eclipse.emf.compare.internal.conflict;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Predicates.and;
import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
import static org.eclipse.emf.compare.ConflictKind.REAL;
-import static org.eclipse.emf.compare.DifferenceKind.DELETE;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
-import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueIs;
import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.List;
@@ -47,7 +41,6 @@ import org.eclipse.emf.compare.internal.ThreeWayTextDiff;
import org.eclipse.emf.compare.utils.ReferenceUtil;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
@@ -233,111 +226,6 @@ public abstract class AbstractConflictSearch<T extends Diff> {
}
/**
- * This will be used whenever we check for conflictual MOVEs in order to determine whether we have a
- * pseudo conflict or a real conflict.
- * <p>
- * Namely, this will retrieve the value of the given {@code feature} on the right and left sides of the
- * given {@code match}, then check whether the two given values are on the same index.
- * </p>
- * <p>
- * Note that no sanity checks will be made on either the match's sides or the feature.
- * </p>
- *
- * @param match
- * Match for which we need to check a feature.
- * @param feature
- * The feature which values we need to check.
- * @param value1
- * First of the two values which index we are to compare.
- * @param value2
- * Second of the two values which index we are to compare.
- * @return {@code true} if the two given values are located at the same index in the given feature's
- * values list, {@code false} otherwise.
- */
- protected boolean matchingIndices(Match match, EStructuralFeature feature, Object value1, Object value2) {
- boolean matching = false;
- if (feature.isMany()) {
- @SuppressWarnings("unchecked")
- final List<Object> leftValues = (List<Object>)ReferenceUtil.safeEGet(match.getLeft(), feature);
- @SuppressWarnings("unchecked")
- final List<Object> rightValues = (List<Object>)ReferenceUtil.safeEGet(match.getRight(), feature);
-
- // FIXME the detection _will_ fail for non-unique lists with multiple identical values...
- int leftIndex = -1;
- int rightIndex = -1;
- for (int i = 0; i < leftValues.size(); i++) {
- final Object left = leftValues.get(i);
- if (comparison.getEqualityHelper().matchingValues(left, value1)) {
- break;
- } else if (hasDiff(match, feature, left) || hasDeleteDiff(match, feature, left)) {
- // Do not increment.
- } else {
- leftIndex++;
- }
- }
- for (int i = 0; i < rightValues.size(); i++) {
- final Object right = rightValues.get(i);
- if (comparison.getEqualityHelper().matchingValues(right, value2)) {
- break;
- } else if (hasDiff(match, feature, right) || hasDeleteDiff(match, feature, right)) {
- // Do not increment.
- } else {
- rightIndex++;
- }
- }
- matching = leftIndex == rightIndex;
- } else {
- matching = true;
- }
- return matching;
- }
-
- /**
- * Checks whether the given {@code match} presents a difference of any kind on the given {@code feature}'s
- * {@code value}.
- *
- * @param match
- * The match which differences we'll check.
- * @param feature
- * The feature on which we expect a difference.
- * @param value
- * The value we expect to have changed inside {@code feature}.
- * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
- */
- protected boolean hasDiff(Match match, EStructuralFeature feature, Object value) {
- return Iterables.any(match.getDifferences(), and(onFeature(feature.getName()), valueIs(value)));
- }
-
- /**
- * Checks whether the given {@code value} has been deleted from the given {@code feature} of {@code match}
- * .
- *
- * @param match
- * The match which differences we'll check.
- * @param feature
- * The feature on which we expect a difference.
- * @param value
- * The value we expect to have been removed from {@code feature}.
- * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
- */
- protected boolean hasDeleteDiff(Match match, EStructuralFeature feature, Object value) {
- checkArgument(match.getComparison() == comparison);
- final Object expectedValue;
- if (value instanceof EObject && comparison.isThreeWay()) {
- final Match valueMatch = comparison.getMatch((EObject)value);
- if (valueMatch != null) {
- expectedValue = valueMatch.getOrigin();
- } else {
- expectedValue = value;
- }
- } else {
- expectedValue = value;
- }
- return Iterables.any(match.getDifferences(),
- and(onFeature(feature.getName()), valueIs(expectedValue), ofKind(DELETE)));
- }
-
- /**
* This will be called whenever we detect a new conflict in order to create (or update) the actual
* association.
*
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java
index 30270e033..ba39f3142 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java
@@ -21,6 +21,7 @@ import static org.eclipse.emf.compare.DifferenceKind.MOVE;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.collect.Iterables;
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java
index ddaa96e2b..30d8c7523 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/ContainmentRefChangeConflictSearch.java
@@ -23,6 +23,7 @@ import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueMatches;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.collect.Iterables;
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java
index c3bb489f9..b42c2e5b0 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/FeatureMapChangeConflictSearch.java
@@ -22,6 +22,7 @@ import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueMatches;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.collect.Iterables;
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java
index 185b618ac..0a220f043 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/NonContainmentRefChangeConflictSearch.java
@@ -21,6 +21,7 @@ import static org.eclipse.emf.compare.DifferenceKind.MOVE;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
import static org.eclipse.emf.compare.utils.EMFComparePredicates.possiblyConflictingWith;
+import static org.eclipse.emf.compare.utils.MatchUtil.matchingIndices;
import com.google.common.collect.Iterables;
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/postprocessor/factories/AbstractChangeFactory.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/postprocessor/factories/AbstractChangeFactory.java
index 1cc33fe70..888e811ad 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/postprocessor/factories/AbstractChangeFactory.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/postprocessor/factories/AbstractChangeFactory.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2015 Obeo.
+ * Copyright (c) 2013, 2016 Obeo and others.
* 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
@@ -7,13 +7,13 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Philip Langer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.internal.postprocessor.factories;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -73,18 +73,6 @@ public abstract class AbstractChangeFactory implements IChangeFactory {
setRefiningChanges(ret, extensionKind, input);
- // FIXME: Maybe it would be better to get all conflict objects from all conflicting unit differences
- // and
- // create a new conflict object with these differences, to set on the macroscopic change (ret).
- Diff conflictingDiff = Iterators.find(ret.getRefinedBy().iterator(), new Predicate<Diff>() {
- public boolean apply(Diff difference) {
- return difference.getConflict() != null;
- }
- }, null);
- if (conflictingDiff != null) {
- ret.setConflict(conflictingDiff.getConflict());
- }
-
return ret;
}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
index 7bb3f646f..89f2e2501 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2014 Obeo and others.
+ * Copyright (c) 2012, 2016 Obeo and others.
* 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
@@ -13,6 +13,8 @@
*******************************************************************************/
package org.eclipse.emf.compare.internal.utils;
+import static com.google.common.collect.Lists.newArrayList;
+
import com.google.common.base.Predicate;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Iterables;
@@ -24,6 +26,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
@@ -67,6 +70,70 @@ public final class DiffUtil {
}
/**
+ * The set of all the diffs that refine the given diff or one of its refining diffs, recursively.
+ *
+ * @param diff
+ * The diff for which all the refining diffs are seeked
+ * @return A set of all the refining diffs (as opposed to getting only the 1st level of refining diffs
+ * that would be obtained by calling getRefinedBy() on diff.
+ */
+ public static Set<Diff> getAllRefiningDiffs(Diff diff) {
+ Set<Diff> result = new LinkedHashSet<Diff>();
+ if (diff != null) {
+ for (Diff refiningDiff : diff.getRefinedBy()) {
+ result.add(refiningDiff);
+ if (!refiningDiff.getRefinedBy().isEmpty()) {
+ result.addAll(getAllRefiningDiffs(refiningDiff));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Determines the root refined diff of a refining diff, i.e. a refined diff that is not refining another
+ * diff.
+ *
+ * @param diff
+ * The diff for which the root refined diffs are to be determined
+ * @return The root refined diffs of the provided (refining) diff, as a list. Never <code>null</code>.
+ * Empty if the provided diff does not refine any diff.
+ */
+ public static List<Diff> getRootRefinedDiffs(Diff diff) {
+ List<Diff> rootRefinedDiffs = newArrayList();
+ for (Diff refinedDiff : diff.getRefines()) {
+ if (refinedDiff.getRefines().isEmpty()) {
+ rootRefinedDiffs.add(refinedDiff);
+ } else {
+ rootRefinedDiffs.addAll(getRootRefinedDiffs(refinedDiff));
+ }
+ }
+ return rootRefinedDiffs;
+ }
+
+ /**
+ * The set of all the diffs that refine the given diff or one of its refining diffs, recursively.
+ *
+ * @param diff
+ * The diff for which all the refining diffs are seeked
+ * @return A set of all the refining diffs (as opposed to getting only the 1st level of refining diffs
+ * that would be obtained by calling getRefinedBy() on diff.
+ */
+ public static Set<Diff> getAllAtomicRefiningDiffs(Diff diff) {
+ Set<Diff> result = new LinkedHashSet<Diff>();
+ if (diff != null) {
+ for (Diff refiningDiff : diff.getRefinedBy()) {
+ if (refiningDiff.getRefinedBy().isEmpty()) {
+ result.add(refiningDiff);
+ } else {
+ result.addAll(getAllAtomicRefiningDiffs(refiningDiff));
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
* Computes the dice coefficient between the two given String's bigrams.
* <p>
* This implementation is case sensitive.
@@ -77,10 +144,10 @@ public final class DiffUtil {
* want the similarity between <code>"v1"</code> and <code>"v2"</code> to be <code>0.5</code> and not
* <code>0</code>. However, we also want <code>"v1"</code> and <code>"v2"</code> to be "more similar" to
* each other than <code>"v"</code> and <code>"v2"</code> and <code>"v1"</code> and <code>"v11"</code> to
- * be "more similar" than <code>"v"</code> and <code>"v11"</code> while this latter also needs to be
- * "less similar" than <code>"v1"</code> and <code>"v2"</code>. This requires a slightly different
- * handling for comparisons with a "single character"-long string than for "two character"-long ones. A
- * set of invariants we wish to meet can be found in the unit tests.
+ * be "more similar" than <code>"v"</code> and <code>"v11"</code> while this latter also needs to be "less
+ * similar" than <code>"v1"</code> and <code>"v2"</code>. This requires a slightly different handling for
+ * comparisons with a "single character"-long string than for "two character"-long ones. A set of
+ * invariants we wish to meet can be found in the unit tests.
* </p>
*
* @param first
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/Graph.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/Graph.java
index 92c61d9bc..6abebbd13 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/Graph.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/Graph.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2015 Obeo and others.
+ * Copyright (c) 2013, 2016 Obeo and others.
* 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
@@ -19,6 +19,8 @@ import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
import java.util.Collection;
import java.util.Collections;
@@ -1081,7 +1083,8 @@ public class Graph<E> implements IGraph<E> {
}
currentIterator = Iterators.filter(difference.iterator(), new Predicate<Node<E>>() {
public boolean apply(Node<E> input) {
- return consumedNodes.containsAll(input.getParents());
+ SetView<Node<E>> trueParents = Sets.difference(input.getParents(), input.getChildren());
+ return consumedNodes.containsAll(trueParents);
}
});
nextIterable.clear();
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/MatchOfContainmentReferenceChangeAdapter.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/MatchOfContainmentReferenceChangeAdapter.java
new file mode 100644
index 000000000..b1a923c63
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/match/MatchOfContainmentReferenceChangeAdapter.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 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.match;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.ReferenceChange;
+
+/**
+ * Specific {@link Adapter} to {@link Match}es that are related to containment {@link ReferenceChange}s (that
+ * are placed in their parent {@link Match}).
+ *
+ * @author <a href="mailto:axel.richard@obeo.fr">Axel Richard</a>
+ */
+public class MatchOfContainmentReferenceChangeAdapter extends AdapterImpl {
+
+ /** The {@link ReferenceChange} to associate with the adapted {@link Match}. */
+ private ReferenceChange referenceChange;
+
+ /**
+ * Constructor.
+ *
+ * @param referenceChange
+ * The {@link ReferenceChange} to associate with the adapted {@link Match}.
+ */
+ public MatchOfContainmentReferenceChangeAdapter(ReferenceChange referenceChange) {
+ super();
+ this.referenceChange = referenceChange;
+ }
+
+ /**
+ * {@inheritDoc} .
+ *
+ * @see org.eclipse.emf.common.notify.impl.AdapterImpl#isAdapterForType(Object)
+ */
+ @Override
+ public boolean isAdapterForType(Object type) {
+ if (type == MatchOfContainmentReferenceChangeAdapter.class) {
+ return true;
+ }
+ return super.isAdapterForType(type);
+ }
+
+ /**
+ * Get the {@link ReferenceChange} to associate with the adapted {@link Match}.
+ *
+ * @return The {@link ReferenceChange} to associate with the adapted {@link Match}.
+ */
+ public ReferenceChange getReferenceChange() {
+ return referenceChange;
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java
index b408d3a85..070ecd6c2 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/EMFComparePredicates.java
@@ -8,18 +8,29 @@
* Contributors:
* Obeo - initial API and implementation
* Stefan Dirix - bug 441172
- * Philip Langer - add containsConflictOfTypes(ConflictKind...)
+ * Philip Langer - add additional predicates
+ * Tanja Mayerhofer - bug 501864
*******************************************************************************/
package org.eclipse.emf.compare.utils;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.and;
+import static com.google.common.base.Predicates.not;
+import static com.google.common.base.Predicates.or;
+import static com.google.common.collect.Iterables.all;
+import static com.google.common.collect.Iterables.any;
+import static org.eclipse.emf.compare.ConflictKind.PSEUDO;
+import static org.eclipse.emf.compare.ConflictKind.REAL;
+import static org.eclipse.emf.compare.DifferenceKind.ADD;
import static org.eclipse.emf.compare.internal.utils.ComparisonUtil.isDeleteOrUnsetDiff;
+import static org.eclipse.emf.compare.internal.utils.DiffUtil.getAllAtomicRefiningDiffs;
+import static org.eclipse.emf.compare.internal.utils.DiffUtil.getAllRefiningDiffs;
import com.google.common.base.Predicate;
import java.util.Arrays;
import java.util.Iterator;
+import java.util.Set;
import org.eclipse.emf.compare.AttributeChange;
import org.eclipse.emf.compare.Conflict;
@@ -342,6 +353,30 @@ public final class EMFComparePredicates {
}
/**
+ * Indicates whether a diff is part of a real add/add conflict.
+ *
+ * @return a predicate to check if a diff belongs to an add/add conflict.
+ * @since 3.4
+ */
+ public static Predicate<Diff> isInRealAddAddConflict() {
+ return new Predicate<Diff>() {
+ public boolean apply(Diff input) {
+ Conflict conflict = input.getConflict();
+ if (conflict != null) {
+ if (conflict.getKind() != REAL) {
+ return false;
+ } else {
+ if (all(conflict.getDifferences(), ofKind(ADD))) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ };
+ }
+
+ /**
* This predicate can be used to check whether a given Diff represents the deletion of a value from a
* multi-valued reference going by {@code referenceName} on an EObject which name matches
* {@code qualifiedName}.
@@ -1108,6 +1143,130 @@ public final class EMFComparePredicates {
}
/**
+ * This predicate can be used to check whether any refining diff of a given diff fulfills the given
+ * predicate.
+ *
+ * @param predicate
+ * The predicate to check.
+ * @return The predicate.
+ * @since 3.4
+ */
+ public static Predicate<Diff> anyRefining(final Predicate<? super Diff> predicate) {
+ return new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return diff != null && any(getAllRefiningDiffs(diff), predicate);
+ }
+ };
+ }
+
+ /**
+ * This predicate can be used to check whether any refined diff of a given diff fulfills the given
+ * predicate.
+ *
+ * @param predicate
+ * The predicate to check.
+ * @return The predicate.
+ * @since 3.4
+ */
+ public static Predicate<Diff> anyRefined(final Predicate<? super Diff> predicate) {
+ return new Predicate<Diff>() {
+ public boolean apply(Diff input) {
+ return input != null && any(input.getRefines(), predicate);
+ }
+ };
+ }
+
+ /**
+ * This predicate can be used to check whether a diff has refiningDiffs AND all these refining diffs
+ * fulfill the given predicate.
+ * <p>
+ * <b>BEWARE: If the given diff has no refining diff, the predicate returns <code>false</code>.</b>
+ * </p>
+ *
+ * @param predicate
+ * The predicate to check on each 'atomic' (i.e. not refined) refining diff.
+ * @return The predicate.
+ * @since 3.4
+ */
+ public static Predicate<Diff> allAtomicRefining(final Predicate<? super Diff> predicate) {
+ return new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ Set<Diff> atomicRefiningDiffs = getAllAtomicRefiningDiffs(diff);
+ if (atomicRefiningDiffs.isEmpty()) {
+ return false;
+ }
+ return all(atomicRefiningDiffs, predicate);
+ }
+ };
+ }
+
+ /**
+ * Check whether a diff is not refined and has a direct conflict of (one of) the given type(s).
+ *
+ * @param kinds
+ * Type(s) of the conflict(s) we seek.
+ * @return The created predicate.
+ * @since 3.4
+ */
+ public static Predicate<Diff> isNotRefinedDirectlyConflicting(final ConflictKind... kinds) {
+ return new Predicate<Diff>() {
+ public boolean apply(Diff input) {
+ return input != null && input.getConflict() != null && input.getRefinedBy().isEmpty()
+ && Arrays.asList(kinds).contains(input.getConflict().getKind());
+ }
+ };
+ }
+
+ /**
+ * This predicate can be used to test if a diff is in a pseudo conflict. Several cases are possible:
+ *
+ * <pre>
+ * - if the diff is not a refined diff and has a direct pseudo conflict (i.e. diff.getConflict = a pseudo conflict)
+ * - if the diff is a refined diff and all its refining diffs are in pseudo conflicts.
+ * The refining diffs must not be part of a real conflict directly or indirectly
+ * </pre>
+ *
+ * @return the predicate
+ * @since 3.4
+ */
+ public static Predicate<Diff> canBeConsideredAsPseudoConflicting() {
+ return or(isNotRefinedDirectlyConflicting(PSEUDO),
+ and(allAtomicRefining(hasConflict(PSEUDO)), hasNoDirectOrIndirectConflict(REAL)));
+ }
+
+ /**
+ * This predicate can be used to check whether a diff is in a conflict directly or indirectly.
+ * <p>
+ * A diff is directly in a conflict if it {@link #hasConflict(ConflictKind...) has a conflict}. A diff is
+ * indirectly in a conflict, if one of its refining diffs is in a conflict.
+ * </p>
+ *
+ * @param kinds
+ * Type(s) of the conflict(s) we seek.
+ * @return The created predicate.
+ * @since 3.4
+ */
+ public static Predicate<? super Diff> hasDirectOrIndirectConflict(final ConflictKind... kinds) {
+ return or(hasConflict(kinds), anyRefining(hasConflict(kinds)));
+ }
+
+ /**
+ * This predicate can be used to check whether a diff is not in a conflict directly or indirectly.
+ * <p>
+ * A diff is directly in a conflict if it {@link #hasConflict(ConflictKind...) has a conflict}. A diff is
+ * indirectly in a conflict, if one of its refining diffs is in a conflict.
+ * </p>
+ *
+ * @param kinds
+ * Type(s) of the conflict(s) we seek.
+ * @return The created predicate.
+ * @since 3.4
+ */
+ public static Predicate<? super Diff> hasNoDirectOrIndirectConflict(final ConflictKind... kinds) {
+ return not(hasDirectOrIndirectConflict(kinds));
+ }
+
+ /**
* This particular predicate will be used to check that a given Diff corresponds to a ReferenceChange on a
* given reference, with known "original" and "changed" values.
*
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java
index 6dffad702..d8a526b16 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/utils/MatchUtil.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2015 Obeo and others.
+ * Copyright (c) 2012, 2016 Obeo and others.
* 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
@@ -11,8 +11,21 @@
*******************************************************************************/
package org.eclipse.emf.compare.utils;
+import static com.google.common.base.Predicates.and;
+import static org.eclipse.emf.compare.DifferenceKind.ADD;
+import static org.eclipse.emf.compare.DifferenceKind.DELETE;
+import static org.eclipse.emf.compare.DifferenceSource.LEFT;
+import static org.eclipse.emf.compare.DifferenceSource.RIGHT;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.CONTAINMENT_REFERENCE_CHANGE;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.onFeature;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.valueIs;
import static org.eclipse.emf.compare.utils.ReferenceUtil.getAsList;
+import com.google.common.collect.Iterables;
+
+import java.util.List;
+
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.AttributeChange;
import org.eclipse.emf.compare.Comparison;
@@ -67,6 +80,127 @@ public final class MatchUtil {
}
/**
+ * This will be used whenever we check for conflictual MOVEs in order to determine whether we have a
+ * pseudo conflict or a real conflict.
+ * <p>
+ * Namely, this will retrieve the value of the given {@code feature} on the right and left sides of the
+ * given {@code match}, then check whether the two given values are on the same index.
+ * </p>
+ * <p>
+ * Note that no sanity checks will be made on either the match's sides or the feature.
+ * </p>
+ *
+ * @param match
+ * Match for which we need to check a feature.
+ * @param feature
+ * The feature which values we need to check.
+ * @param value1
+ * First of the two values which index we are to compare.
+ * @param value2
+ * Second of the two values which index we are to compare.
+ * @return {@code true} if the two given values are located at the same index in the given feature's
+ * values list, {@code false} otherwise.
+ * @since 3.4
+ */
+ public static boolean matchingIndices(Match match, EStructuralFeature feature, Object value1,
+ Object value2) {
+ boolean matching = false;
+ if (feature.isMany()) {
+ // FIXME the detection _will_ fail for non-unique lists with multiple identical values...
+ int leftIndex = computeIndex(match, feature, value1, LEFT);
+ int rightIndex = computeIndex(match, feature, value2, RIGHT);
+ matching = leftIndex == rightIndex;
+ } else {
+ matching = true;
+ }
+ return matching;
+ }
+
+ /**
+ * Compute the index of an object in the list of elements of a given match+feature on a given side. This
+ * index is computed without taking objects that have a diff into account, except if this diff is an ADD.
+ *
+ * @param match
+ * The match
+ * @param feature
+ * The structural feature
+ * @param value
+ * The object the index of which must be computed
+ * @param side
+ * The side on which to compute the index
+ * @return The index of the given object.
+ * @since 3.4
+ */
+ public static int computeIndex(Match match, EStructuralFeature feature, Object value,
+ DifferenceSource side) {
+ Comparison comparison = match.getComparison();
+ int result = -1;
+ @SuppressWarnings("unchecked")
+ final List<Object> sideValues = (List<Object>)ReferenceUtil
+ .safeEGet(MatchUtil.getMatchedObject(match, side), feature);
+ for (int i = 0; i < sideValues.size(); i++) {
+ final Object sideObject = sideValues.get(i);
+ if (comparison.getEqualityHelper().matchingValues(sideObject, value)) {
+ break;
+ } else if ((hasDiff(match, feature, sideObject) && match.getOrigin() != null)
+ || hasDeleteDiff(match, feature, sideObject)) {
+ // Do not increment.
+ } else {
+ result++;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks whether the given {@code value} has been deleted from the given {@code feature} of {@code match}
+ * .
+ *
+ * @param match
+ * The match which differences we'll check.
+ * @param feature
+ * The feature on which we expect a difference.
+ * @param value
+ * The value we expect to have been removed from {@code feature}.
+ * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
+ * @since 3.4
+ */
+ @SuppressWarnings("unchecked")
+ public static boolean hasDeleteDiff(Match match, EStructuralFeature feature, Object value) {
+ Comparison comparison = match.getComparison();
+ final Object expectedValue;
+ if (value instanceof EObject && comparison.isThreeWay()) {
+ final Match valueMatch = comparison.getMatch((EObject)value);
+ if (valueMatch != null) {
+ expectedValue = valueMatch.getOrigin();
+ } else {
+ expectedValue = value;
+ }
+ } else {
+ expectedValue = value;
+ }
+ return Iterables.any(match.getDifferences(),
+ and(onFeature(feature.getName()), valueIs(expectedValue), ofKind(DELETE)));
+ }
+
+ /**
+ * Checks whether the given {@code match} presents a difference of any kind on the given {@code feature}'s
+ * {@code value}.
+ *
+ * @param match
+ * The match which differences we'll check.
+ * @param feature
+ * The feature on which we expect a difference.
+ * @param value
+ * The value we expect to have changed inside {@code feature}.
+ * @return <code>true</code> if there is such a Diff on {@code match}, <code>false</code> otherwise.
+ * @since 3.4
+ */
+ public static boolean hasDiff(Match match, EStructuralFeature feature, Object value) {
+ return Iterables.any(match.getDifferences(), and(onFeature(feature.getName()), valueIs(value)));
+ }
+
+ /**
* From a given mono-valued reference change, get the origin value.
*
* @param comparison
@@ -290,4 +424,22 @@ public final class MatchUtil {
}
}
+ /**
+ * Get the potential ReferenceChanges that represent add/delete containment differences in the parent
+ * Match of the given Match.
+ *
+ * @param match
+ * the given Match.
+ * @return the potential ReferenceChanges that represent add/delete containment differences in the parent
+ * Match of the given Match, <code>null</code> otherwise.
+ */
+ public static Iterable<Diff> findAddOrDeleteContainmentDiffs(Match match) {
+ final EObject container = match.eContainer();
+ if (container instanceof Match) {
+ return Iterables.filter(((Match)container).getDifferences(),
+ and(CONTAINMENT_REFERENCE_CHANGE, ofKind(ADD, DELETE)));
+ }
+ return null;
+ }
+
}

Back to the top