Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlgoubet2019-08-29 09:25:22 -0400
committerlgoubet2019-08-30 08:33:13 -0400
commitb66be13a918e0a83aae89b6f38fa087672e524ee (patch)
treeffa59ef23e99b5846d9b688feb6611fbb3ec5cde
parenta9a46d1dca11195b5c899f5787df0e3ed58f4b99 (diff)
downloadorg.eclipse.emf.compare-b66be13a918e0a83aae89b6f38fa087672e524ee.tar.gz
org.eclipse.emf.compare-b66be13a918e0a83aae89b6f38fa087672e524ee.tar.xz
org.eclipse.emf.compare-b66be13a918e0a83aae89b6f38fa087672e524ee.zip
Fix diff, conflict detection and merging of non-unique attributes
Non-unique multi-valued attributes had been completely ignored during the conception of EMF Compare and thus every step of the process was failing. Change-Id: I09c7ff8cf3eee5fff6c76128a3142a29acb15987
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/TestBasicDifferenceGroupImpl.java8
-rw-r--r--plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/TestReferenceChangeTreeNodeItemProviderSpec.java8
-rw-r--r--plugins/org.eclipse.emf.compare.tests/model/nodes.ecore4
-rw-r--r--plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel14
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/Node.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeEnum.java6
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment2.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapNonContainment.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueEEnumAttribute.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueReference.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedAttribute.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedNonUniqueAttribute.java55
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultipleContainment.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefManyToMany.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToMany.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToOne.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueAttribute.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueContainment.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueEEnumAttribute.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueReference.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesFactory.java9
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesPackage.java107
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainment2Impl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainmentImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapNonContainmentImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueEEnumAttributeImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueReferenceImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedAttributeImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedNonUniqueAttributeImpl.java162
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultipleContainmentImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefManyToManyImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToManyImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToOneImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueAttributeImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueContainmentImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueEEnumAttributeImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueReferenceImpl.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesFactoryImpl.java11
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesPackageImpl.java33
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesAdapterFactory.java18
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesSwitch.java22
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/NonUniqueMultiValuedAttributeTest.java600
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/SingleValuedAttributePseudoConflictTest.java2
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/NonUniqueMultiValuedAttributeInputData.java55
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/left.nodes8
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/origin.nodes8
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/right.nodes8
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/left.nodes12
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/origin.nodes12
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/right.nodes12
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/left.nodes15
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/origin.nodes12
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/right.nodes12
-rw-r--r--plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/suite/AllTests.java5
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java96
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java125
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/conflict/AttributeChangeConflictSearch.java54
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/internal/utils/DiffUtil.java181
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java235
61 files changed, 1770 insertions, 199 deletions
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/TestBasicDifferenceGroupImpl.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/TestBasicDifferenceGroupImpl.java
index 13879b3ae..433271052 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/TestBasicDifferenceGroupImpl.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/TestBasicDifferenceGroupImpl.java
@@ -286,13 +286,13 @@ public class TestBasicDifferenceGroupImpl extends AbstractTestTreeNodeItemProvid
childNode = node.getChildren().get(0);
checkText(childNode, "Periodical -> Item [eClassifiers delete]");
assertEquals(0, childNode.getChildren().size());
- // eSuperTypes add
+ // eSuperTypes delete
childNode = node.getChildren().get(1);
- checkText(childNode, "TitledItem [eSuperTypes add]");
+ checkText(childNode, "Item [eSuperTypes delete]");
assertEquals(0, childNode.getChildren().size());
- // eSuperTypes delete
+ // eSuperTypes add
childNode = node.getChildren().get(2);
- checkText(childNode, "Item [eSuperTypes delete]");
+ checkText(childNode, "TitledItem [eSuperTypes add]");
assertEquals(0, childNode.getChildren().size());
// Periodical.issuesPerYear
diff --git a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/TestReferenceChangeTreeNodeItemProviderSpec.java b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/TestReferenceChangeTreeNodeItemProviderSpec.java
index 2a4c89d5b..0ac322245 100644
--- a/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/TestReferenceChangeTreeNodeItemProviderSpec.java
+++ b/plugins/org.eclipse.emf.compare.rcp.ui.tests/src/org/eclipse/emf/compare/rcp/ui/tests/structuremergeviewer/groups/provider/TestReferenceChangeTreeNodeItemProviderSpec.java
@@ -273,13 +273,13 @@ public class TestReferenceChangeTreeNodeItemProviderSpec extends AbstractTestTre
checkNoChild(node0);
assertNotNull(((Diff)node0.getData()).getConflict());
TreeNode node1 = periodicalChildren.get(1);
- checkRefChange(node1, RIGHT, ADD, "eSuperTypes");
+ checkRefChange(node1, LEFT, DELETE, "eSuperTypes");
checkNoChild(node1);
- assertNotNull(((Diff)node1.getData()).getConflict());
- assertSame(((Diff)node0.getData()).getConflict(), ((Diff)node1.getData()).getConflict());
TreeNode node2 = periodicalChildren.get(2);
- checkRefChange(node2, LEFT, DELETE, "eSuperTypes");
+ checkRefChange(node2, RIGHT, ADD, "eSuperTypes");
checkNoChild(node2);
+ assertNotNull(((Diff)node2.getData()).getConflict());
+ assertSame(((Diff)node0.getData()).getConflict(), ((Diff)node2.getData()).getConflict());
TreeNode node3 = periodicalChildren.get(3);
assertTrue(node3 instanceof MatchNode);
diff --git a/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore b/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore
index d85c30e7a..64d4796d6 100644
--- a/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore
+++ b/plugins/org.eclipse.emf.compare.tests/model/nodes.ecore
@@ -26,6 +26,10 @@
<eStructuralFeatures xsi:type="ecore:EAttribute" name="multiValuedAttribute" upperBound="-1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
+ <eClassifiers xsi:type="ecore:EClass" name="NodeMultiValuedNonUniqueAttribute" eSuperTypes="#//Node">
+ <eStructuralFeatures xsi:type="ecore:EAttribute" name="multiValuedAttribute" unique="false"
+ upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+ </eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="NodeSingleValueReference" eSuperTypes="#//Node">
<eStructuralFeatures xsi:type="ecore:EReference" name="singleValuedReference"
eType="#//Node"/>
diff --git a/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel b/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel
index fac0cb1e2..3fc6d78a3 100644
--- a/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel
+++ b/plugins/org.eclipse.emf.compare.tests/model/nodes.genmodel
@@ -8,6 +8,11 @@
<genPackages prefix="Nodes" basePackage="org.eclipse.emf.compare.tests" resource="XMI"
disposableProviderFactory="true" contentTypeIdentifier="org.eclipse.emf.compare.test.nodes.contenttype"
ecorePackage="nodes.ecore#/">
+ <genEnums typeSafeEnumCompatible="false" ecoreEnum="nodes.ecore#//NodeEnum">
+ <genEnumLiterals ecoreEnumLiteral="nodes.ecore#//NodeEnum/A"/>
+ <genEnumLiterals ecoreEnumLiteral="nodes.ecore#//NodeEnum/B"/>
+ <genEnumLiterals ecoreEnumLiteral="nodes.ecore#//NodeEnum/C"/>
+ </genEnums>
<genClasses ecoreClass="nodes.ecore#//Node">
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//Node/name"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference nodes.ecore#//Node/containmentRef1"/>
@@ -25,6 +30,9 @@
<genClasses ecoreClass="nodes.ecore#//NodeMultiValuedAttribute">
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//NodeMultiValuedAttribute/multiValuedAttribute"/>
</genClasses>
+ <genClasses ecoreClass="nodes.ecore#//NodeMultiValuedNonUniqueAttribute">
+ <genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//NodeMultiValuedNonUniqueAttribute/multiValuedAttribute"/>
+ </genClasses>
<genClasses ecoreClass="nodes.ecore#//NodeSingleValueReference">
<genFeatures notify="false" createChild="false" propertySortChoices="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeSingleValueReference/singleValuedReference"/>
</genClasses>
@@ -58,5 +66,11 @@
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeFeatureMapContainment2/multiple"/>
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference nodes.ecore#//NodeFeatureMapContainment2/single"/>
</genClasses>
+ <genClasses ecoreClass="nodes.ecore#//NodeSingleValueEEnumAttribute">
+ <genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//NodeSingleValueEEnumAttribute/singlevalueEEnumAttribute"/>
+ </genClasses>
+ <genClasses ecoreClass="nodes.ecore#//NodeMultiValueEEnumAttribute">
+ <genFeatures createChild="false" ecoreFeature="ecore:EAttribute nodes.ecore#//NodeMultiValueEEnumAttribute/multiValueEEnumAttribute"/>
+ </genClasses>
</genPackages>
</genmodel:GenModel>
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/Node.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/Node.java
index 8b9626a4a..4de8697dd 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/Node.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/Node.java
@@ -20,11 +20,11 @@ import org.eclipse.emf.ecore.EObject;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.Node#getName <em>Name</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.Node#getContainmentRef1 <em>Containment Ref1</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNode()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeEnum.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeEnum.java
index 836029f92..d5d321330 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeEnum.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeEnum.java
@@ -133,6 +133,8 @@ public enum NodeEnum implements Enumerator {
* Returns the '<em><b>Node Enum</b></em>' literal with the specified literal value.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
+ * @param literal the literal.
+ * @return the matching enumerator or <code>null</code>.
* @generated
*/
public static NodeEnum get(String literal) {
@@ -149,6 +151,8 @@ public enum NodeEnum implements Enumerator {
* Returns the '<em><b>Node Enum</b></em>' literal with the specified name.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
+ * @param name the name.
+ * @return the matching enumerator or <code>null</code>.
* @generated
*/
public static NodeEnum getByName(String name) {
@@ -165,6 +169,8 @@ public enum NodeEnum implements Enumerator {
* Returns the '<em><b>Node Enum</b></em>' literal with the specified integer value.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
+ * @param value the integer value.
+ * @return the matching enumerator or <code>null</code>.
* @generated
*/
public static NodeEnum get(int value) {
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment.java
index 20e562133..799b1c4c7 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment.java
@@ -20,12 +20,12 @@ import org.eclipse.emf.ecore.util.FeatureMap;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment#getMap <em>Map</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment#getFirstKey <em>First Key</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment#getSecondKey <em>Second Key</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeFeatureMapContainment()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment2.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment2.java
index 265237587..cb0b073f6 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment2.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapContainment2.java
@@ -19,12 +19,12 @@ import org.eclipse.emf.ecore.util.FeatureMap;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment2#getMap2 <em>Map2</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment2#getMultiple <em>Multiple</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapContainment2#getSingle <em>Single</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeFeatureMapContainment2()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapNonContainment.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapNonContainment.java
index 68d039507..e879c10f0 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapNonContainment.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeFeatureMapNonContainment.java
@@ -20,12 +20,12 @@ import org.eclipse.emf.ecore.util.FeatureMap;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapNonContainment#getMapNC <em>Map NC</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapNonContainment#getFirstKeyNC <em>First Key NC</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeFeatureMapNonContainment#getSecondKeyNC <em>Second Key NC</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeFeatureMapNonContainment()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueEEnumAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueEEnumAttribute.java
index 1b3993998..6523f67e1 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueEEnumAttribute.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueEEnumAttribute.java
@@ -19,10 +19,10 @@ import org.eclipse.emf.common.util.EList;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValueEEnumAttribute#getMultiValueEEnumAttribute <em>Multi Value EEnum Attribute</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValueEEnumAttribute()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueReference.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueReference.java
index 57d33c54e..35f409200 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueReference.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValueReference.java
@@ -19,10 +19,10 @@ import org.eclipse.emf.common.util.EList;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValueReference#getMultiValuedReference <em>Multi Valued Reference</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValueReference()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedAttribute.java
index 4a7eec1a7..7d14d9f3c 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedAttribute.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedAttribute.java
@@ -19,10 +19,10 @@ import org.eclipse.emf.common.util.EList;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedAttribute#getMultiValuedAttribute <em>Multi Valued Attribute</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValuedAttribute()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedNonUniqueAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedNonUniqueAttribute.java
new file mode 100644
index 000000000..25c3c91fe
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultiValuedNonUniqueAttribute.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2011, 2012 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ */
+package org.eclipse.emf.compare.tests.nodes;
+
+import org.eclipse.emf.common.util.EList;
+
+/**
+ * <!-- begin-user-doc -->
+ * A representation of the model object '<em><b>Node Multi Valued Non Unique Attribute</b></em>'.
+ * <!-- end-user-doc -->
+ *
+ * <p>
+ * The following features are supported:
+ * </p>
+ * <ul>
+ * <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute#getMultiValuedAttribute <em>Multi Valued Attribute</em>}</li>
+ * </ul>
+ *
+ * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValuedNonUniqueAttribute()
+ * @model
+ * @generated
+ */
+public interface NodeMultiValuedNonUniqueAttribute extends Node {
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ String copyright = "Copyright (c) 2011, 2012 Obeo.\r\nAll rights reserved. This program and the accompanying materials\r\nare made available under the terms of the Eclipse Public License v1.0\r\nwhich accompanies this distribution, and is available at\r\nhttp://www.eclipse.org/legal/epl-v10.html\r\n\r\nContributors:\r\n Obeo - initial API and implementation"; //$NON-NLS-1$
+
+ /**
+ * Returns the value of the '<em><b>Multi Valued Attribute</b></em>' attribute list.
+ * The list contents are of type {@link java.lang.String}.
+ * <!-- begin-user-doc -->
+ * <p>
+ * If the meaning of the '<em>Multi Valued Attribute</em>' attribute list isn't clear,
+ * there really should be more of a description here...
+ * </p>
+ * <!-- end-user-doc -->
+ * @return the value of the '<em>Multi Valued Attribute</em>' attribute list.
+ * @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute()
+ * @model unique="false"
+ * @generated
+ */
+ EList<String> getMultiValuedAttribute();
+
+} // NodeMultiValuedNonUniqueAttribute
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultipleContainment.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultipleContainment.java
index 64526dd40..c66759e3c 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultipleContainment.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeMultipleContainment.java
@@ -19,11 +19,11 @@ import org.eclipse.emf.common.util.EList;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultipleContainment#getContainmentRef2 <em>Containment Ref2</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeMultipleContainment#getContainmentRef3 <em>Containment Ref3</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeMultipleContainment()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefManyToMany.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefManyToMany.java
index 836a13a92..2cf9120f7 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefManyToMany.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefManyToMany.java
@@ -19,11 +19,11 @@ import org.eclipse.emf.common.util.EList;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefManyToMany#getSource <em>Source</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefManyToMany#getDestination <em>Destination</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeOppositeRefManyToMany()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToMany.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToMany.java
index ce511a572..4b6d88861 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToMany.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToMany.java
@@ -19,11 +19,11 @@ import org.eclipse.emf.common.util.EList;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToMany#getSource <em>Source</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToMany#getDestination <em>Destination</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeOppositeRefOneToMany()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToOne.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToOne.java
index 4531296b1..49d09dac2 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToOne.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeOppositeRefOneToOne.java
@@ -18,11 +18,11 @@ package org.eclipse.emf.compare.tests.nodes;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToOne#getSource <em>Source</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToOne#getDestination <em>Destination</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeOppositeRefOneToOne()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueAttribute.java
index 7a4942d02..178bf0b73 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueAttribute.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueAttribute.java
@@ -18,10 +18,10 @@ package org.eclipse.emf.compare.tests.nodes;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueAttribute#getSingleValuedAttribute <em>Single Valued Attribute</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeSingleValueAttribute()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueContainment.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueContainment.java
index 11c04755e..20b44792c 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueContainment.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueContainment.java
@@ -18,10 +18,10 @@ package org.eclipse.emf.compare.tests.nodes;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueContainment#getSingleValueContainment <em>Single Value Containment</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeSingleValueContainment()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueEEnumAttribute.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueEEnumAttribute.java
index 0fc9a5a69..cd69bf467 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueEEnumAttribute.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueEEnumAttribute.java
@@ -18,10 +18,10 @@ package org.eclipse.emf.compare.tests.nodes;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueEEnumAttribute#getSinglevalueEEnumAttribute <em>Singlevalue EEnum Attribute</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeSingleValueEEnumAttribute()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueReference.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueReference.java
index 598afc863..07173a36b 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueReference.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodeSingleValueReference.java
@@ -18,10 +18,10 @@ package org.eclipse.emf.compare.tests.nodes;
*
* <p>
* The following features are supported:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueReference#getSingleValuedReference <em>Single Valued Reference</em>}</li>
* </ul>
- * </p>
*
* @see org.eclipse.emf.compare.tests.nodes.NodesPackage#getNodeSingleValueReference()
* @model
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesFactory.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesFactory.java
index 9827080d7..eb42023ff 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesFactory.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesFactory.java
@@ -82,6 +82,15 @@ public interface NodesFactory extends EFactory {
NodeMultiValuedAttribute createNodeMultiValuedAttribute();
/**
+ * Returns a new object of class '<em>Node Multi Valued Non Unique Attribute</em>'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @return a new object of class '<em>Node Multi Valued Non Unique Attribute</em>'.
+ * @generated
+ */
+ NodeMultiValuedNonUniqueAttribute createNodeMultiValuedNonUniqueAttribute();
+
+ /**
* Returns a new object of class '<em>Node Single Value Reference</em>'.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesPackage.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesPackage.java
index f1237c98f..57e2cf759 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesPackage.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/NodesPackage.java
@@ -310,6 +310,52 @@ public interface NodesPackage extends EPackage {
int NODE_MULTI_VALUED_ATTRIBUTE_FEATURE_COUNT = NODE_FEATURE_COUNT + 1;
/**
+ * The meta object id for the '{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl <em>Node Multi Valued Non Unique Attribute</em>}' class.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @see org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl
+ * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeMultiValuedNonUniqueAttribute()
+ * @generated
+ */
+ int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE = 5;
+
+ /**
+ * The feature id for the '<em><b>Name</b></em>' attribute.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ * @ordered
+ */
+ int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__NAME = NODE__NAME;
+
+ /**
+ * The feature id for the '<em><b>Containment Ref1</b></em>' containment reference list.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ * @ordered
+ */
+ int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__CONTAINMENT_REF1 = NODE__CONTAINMENT_REF1;
+
+ /**
+ * The feature id for the '<em><b>Multi Valued Attribute</b></em>' attribute list.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ * @ordered
+ */
+ int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE = NODE_FEATURE_COUNT + 0;
+
+ /**
+ * The number of structural features of the '<em>Node Multi Valued Non Unique Attribute</em>' class.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ * @ordered
+ */
+ int NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE_FEATURE_COUNT = NODE_FEATURE_COUNT + 1;
+
+ /**
* The meta object id for the '{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueReferenceImpl <em>Node Single Value Reference</em>}' class.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
@@ -317,7 +363,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeSingleValueReference()
* @generated
*/
- int NODE_SINGLE_VALUE_REFERENCE = 5;
+ int NODE_SINGLE_VALUE_REFERENCE = 6;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -363,7 +409,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeMultiValueReference()
* @generated
*/
- int NODE_MULTI_VALUE_REFERENCE = 6;
+ int NODE_MULTI_VALUE_REFERENCE = 7;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -409,7 +455,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeOppositeRefOneToOne()
* @generated
*/
- int NODE_OPPOSITE_REF_ONE_TO_ONE = 7;
+ int NODE_OPPOSITE_REF_ONE_TO_ONE = 8;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -464,7 +510,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeOppositeRefOneToMany()
* @generated
*/
- int NODE_OPPOSITE_REF_ONE_TO_MANY = 8;
+ int NODE_OPPOSITE_REF_ONE_TO_MANY = 9;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -519,7 +565,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeOppositeRefManyToMany()
* @generated
*/
- int NODE_OPPOSITE_REF_MANY_TO_MANY = 9;
+ int NODE_OPPOSITE_REF_MANY_TO_MANY = 10;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -574,7 +620,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeFeatureMapContainment()
* @generated
*/
- int NODE_FEATURE_MAP_CONTAINMENT = 10;
+ int NODE_FEATURE_MAP_CONTAINMENT = 11;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -638,7 +684,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeFeatureMapNonContainment()
* @generated
*/
- int NODE_FEATURE_MAP_NON_CONTAINMENT = 11;
+ int NODE_FEATURE_MAP_NON_CONTAINMENT = 12;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -702,7 +748,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeFeatureMapContainment2()
* @generated
*/
- int NODE_FEATURE_MAP_CONTAINMENT2 = 12;
+ int NODE_FEATURE_MAP_CONTAINMENT2 = 13;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -767,7 +813,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeSingleValueEEnumAttribute()
* @generated
*/
- int NODE_SINGLE_VALUE_EENUM_ATTRIBUTE = 13;
+ int NODE_SINGLE_VALUE_EENUM_ATTRIBUTE = 14;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -813,7 +859,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeMultiValueEEnumAttribute()
* @generated
*/
- int NODE_MULTI_VALUE_EENUM_ATTRIBUTE = 14;
+ int NODE_MULTI_VALUE_EENUM_ATTRIBUTE = 15;
/**
* The feature id for the '<em><b>Name</b></em>' attribute.
@@ -859,7 +905,7 @@ public interface NodesPackage extends EPackage {
* @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeEnum()
* @generated
*/
- int NODE_ENUM = 15;
+ int NODE_ENUM = 16;
/**
@@ -990,6 +1036,27 @@ public interface NodesPackage extends EPackage {
EAttribute getNodeMultiValuedAttribute_MultiValuedAttribute();
/**
+ * Returns the meta object for class '{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute <em>Node Multi Valued Non Unique Attribute</em>}'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @return the meta object for class '<em>Node Multi Valued Non Unique Attribute</em>'.
+ * @see org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute
+ * @generated
+ */
+ EClass getNodeMultiValuedNonUniqueAttribute();
+
+ /**
+ * Returns the meta object for the attribute list '{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute#getMultiValuedAttribute <em>Multi Valued Attribute</em>}'.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @return the meta object for the attribute list '<em>Multi Valued Attribute</em>'.
+ * @see org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute#getMultiValuedAttribute()
+ * @see #getNodeMultiValuedNonUniqueAttribute()
+ * @generated
+ */
+ EAttribute getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute();
+
+ /**
* Returns the meta object for class '{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueReference <em>Node Single Value Reference</em>}'.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
@@ -1437,6 +1504,24 @@ public interface NodesPackage extends EPackage {
EAttribute NODE_MULTI_VALUED_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE = eINSTANCE.getNodeMultiValuedAttribute_MultiValuedAttribute();
/**
+ * The meta object literal for the '{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl <em>Node Multi Valued Non Unique Attribute</em>}' class.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @see org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl
+ * @see org.eclipse.emf.compare.tests.nodes.impl.NodesPackageImpl#getNodeMultiValuedNonUniqueAttribute()
+ * @generated
+ */
+ EClass NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE = eINSTANCE.getNodeMultiValuedNonUniqueAttribute();
+
+ /**
+ * The meta object literal for the '<em><b>Multi Valued Attribute</b></em>' attribute list feature.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ EAttribute NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE = eINSTANCE.getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute();
+
+ /**
* The meta object literal for the '{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueReferenceImpl <em>Node Single Value Reference</em>}' class.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainment2Impl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainment2Impl.java
index d3e60c831..390692188 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainment2Impl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainment2Impl.java
@@ -29,12 +29,12 @@ import org.eclipse.emf.ecore.util.InternalEList;
* <em><b>Node Feature Map Containment2</b></em>'. <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainment2Impl#getMap2 <em>Map2</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainment2Impl#getMultiple <em>Multiple</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainment2Impl#getSingle <em>Single</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainmentImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainmentImpl.java
index 2cc9138c5..2afbd09d0 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainmentImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapContainmentImpl.java
@@ -29,12 +29,12 @@ import org.eclipse.emf.ecore.util.InternalEList;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainmentImpl#getMap <em>Map</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainmentImpl#getFirstKey <em>First Key</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapContainmentImpl#getSecondKey <em>Second Key</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapNonContainmentImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapNonContainmentImpl.java
index 91f1ddf90..41b092a1e 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapNonContainmentImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeFeatureMapNonContainmentImpl.java
@@ -29,12 +29,12 @@ import org.eclipse.emf.ecore.util.InternalEList;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapNonContainmentImpl#getMapNC <em>Map NC</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapNonContainmentImpl#getFirstKeyNC <em>First Key NC</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeFeatureMapNonContainmentImpl#getSecondKeyNC <em>Second Key NC</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeImpl.java
index d89af6dfb..c33ddba56 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeImpl.java
@@ -30,11 +30,11 @@ import org.eclipse.emf.ecore.util.InternalEList;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeImpl#getName <em>Name</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeImpl#getContainmentRef1 <em>Containment Ref1</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueEEnumAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueEEnumAttributeImpl.java
index b0c247574..758bbe3a4 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueEEnumAttributeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueEEnumAttributeImpl.java
@@ -28,10 +28,10 @@ import org.eclipse.emf.ecore.util.EDataTypeUniqueEList;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValueEEnumAttributeImpl#getMultiValueEEnumAttribute <em>Multi Value EEnum Attribute</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueReferenceImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueReferenceImpl.java
index 1193f31f3..1e110c3d4 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueReferenceImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValueReferenceImpl.java
@@ -25,10 +25,10 @@ import org.eclipse.emf.ecore.util.EObjectResolvingEList;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValueReferenceImpl#getMultiValuedReference <em>Multi Valued Reference</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedAttributeImpl.java
index cef4fa91b..f7e4db40a 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedAttributeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedAttributeImpl.java
@@ -24,10 +24,10 @@ import org.eclipse.emf.ecore.util.EDataTypeUniqueEList;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedAttributeImpl#getMultiValuedAttribute <em>Multi Valued Attribute</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedNonUniqueAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedNonUniqueAttributeImpl.java
new file mode 100644
index 000000000..474b74354
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultiValuedNonUniqueAttributeImpl.java
@@ -0,0 +1,162 @@
+/**
+ * Copyright (c) 2011, 2012 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ */
+package org.eclipse.emf.compare.tests.nodes.impl;
+
+import java.util.Collection;
+
+import org.eclipse.emf.common.util.EList;
+
+import org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute;
+import org.eclipse.emf.compare.tests.nodes.NodesPackage;
+
+import org.eclipse.emf.ecore.EClass;
+
+import org.eclipse.emf.ecore.util.EDataTypeEList;
+
+/**
+ * <!-- begin-user-doc -->
+ * An implementation of the model object '<em><b>Node Multi Valued Non Unique Attribute</b></em>'.
+ * <!-- end-user-doc -->
+ * <p>
+ * The following features are implemented:
+ * </p>
+ * <ul>
+ * <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultiValuedNonUniqueAttributeImpl#getMultiValuedAttribute <em>Multi Valued Attribute</em>}</li>
+ * </ul>
+ *
+ * @generated
+ */
+public class NodeMultiValuedNonUniqueAttributeImpl extends NodeImpl implements NodeMultiValuedNonUniqueAttribute {
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ public static final String copyright = "Copyright (c) 2011, 2012 Obeo.\r\nAll rights reserved. This program and the accompanying materials\r\nare made available under the terms of the Eclipse Public License v1.0\r\nwhich accompanies this distribution, and is available at\r\nhttp://www.eclipse.org/legal/epl-v10.html\r\n\r\nContributors:\r\n Obeo - initial API and implementation"; //$NON-NLS-1$
+
+ /**
+ * The cached value of the '{@link #getMultiValuedAttribute() <em>Multi Valued Attribute</em>}' attribute list.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @see #getMultiValuedAttribute()
+ * @generated
+ * @ordered
+ */
+ protected EList<String> multiValuedAttribute;
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ protected NodeMultiValuedNonUniqueAttributeImpl() {
+ super();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ protected EClass eStaticClass() {
+ return NodesPackage.Literals.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ public EList<String> getMultiValuedAttribute() {
+ if (multiValuedAttribute == null) {
+ multiValuedAttribute = new EDataTypeEList<String>(String.class, this, NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE);
+ }
+ return multiValuedAttribute;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public Object eGet(int featureID, boolean resolve, boolean coreType) {
+ switch (featureID) {
+ case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE:
+ return getMultiValuedAttribute();
+ }
+ return super.eGet(featureID, resolve, coreType);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void eSet(int featureID, Object newValue) {
+ switch (featureID) {
+ case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE:
+ getMultiValuedAttribute().clear();
+ getMultiValuedAttribute().addAll((Collection<? extends String>)newValue);
+ return;
+ }
+ super.eSet(featureID, newValue);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public void eUnset(int featureID) {
+ switch (featureID) {
+ case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE:
+ getMultiValuedAttribute().clear();
+ return;
+ }
+ super.eUnset(featureID);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public boolean eIsSet(int featureID) {
+ switch (featureID) {
+ case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE:
+ return multiValuedAttribute != null && !multiValuedAttribute.isEmpty();
+ }
+ return super.eIsSet(featureID);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public String toString() {
+ if (eIsProxy()) return super.toString();
+
+ StringBuffer result = new StringBuffer(super.toString());
+ result.append(" (multiValuedAttribute: "); //$NON-NLS-1$
+ result.append(multiValuedAttribute);
+ result.append(')');
+ return result.toString();
+ }
+
+} //NodeMultiValuedNonUniqueAttributeImpl
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultipleContainmentImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultipleContainmentImpl.java
index 1f1c58834..ef72bfc82 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultipleContainmentImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeMultipleContainmentImpl.java
@@ -28,11 +28,11 @@ import org.eclipse.emf.ecore.util.InternalEList;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultipleContainmentImpl#getContainmentRef2 <em>Containment Ref2</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeMultipleContainmentImpl#getContainmentRef3 <em>Containment Ref3</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefManyToManyImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefManyToManyImpl.java
index 8069746ea..efa564fc2 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefManyToManyImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefManyToManyImpl.java
@@ -27,11 +27,11 @@ import org.eclipse.emf.ecore.util.InternalEList;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefManyToManyImpl#getSource <em>Source</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefManyToManyImpl#getDestination <em>Destination</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToManyImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToManyImpl.java
index a37ca2c14..e6de81557 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToManyImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToManyImpl.java
@@ -29,11 +29,11 @@ import org.eclipse.emf.ecore.util.InternalEList;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefOneToManyImpl#getSource <em>Source</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefOneToManyImpl#getDestination <em>Destination</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToOneImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToOneImpl.java
index 7f906e1a9..eada64e31 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToOneImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeOppositeRefOneToOneImpl.java
@@ -24,11 +24,11 @@ import org.eclipse.emf.ecore.impl.ENotificationImpl;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefOneToOneImpl#getSource <em>Source</em>}</li>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeOppositeRefOneToOneImpl#getDestination <em>Destination</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueAttributeImpl.java
index 5deaeab50..d8a0fc10c 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueAttributeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueAttributeImpl.java
@@ -22,10 +22,10 @@ import org.eclipse.emf.ecore.impl.ENotificationImpl;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueAttributeImpl#getSingleValuedAttribute <em>Single Valued Attribute</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueContainmentImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueContainmentImpl.java
index a7d8ed3d8..fc194f15e 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueContainmentImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueContainmentImpl.java
@@ -25,10 +25,10 @@ import org.eclipse.emf.ecore.impl.ENotificationImpl;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueContainmentImpl#getSingleValueContainment <em>Single Value Containment</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueEEnumAttributeImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueEEnumAttributeImpl.java
index 81a13749a..ab5226471 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueEEnumAttributeImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueEEnumAttributeImpl.java
@@ -26,10 +26,10 @@ import org.eclipse.emf.ecore.impl.ENotificationImpl;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueEEnumAttributeImpl#getSinglevalueEEnumAttribute <em>Singlevalue EEnum Attribute</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueReferenceImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueReferenceImpl.java
index c282695cc..2bd13d01f 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueReferenceImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodeSingleValueReferenceImpl.java
@@ -24,10 +24,10 @@ import org.eclipse.emf.ecore.impl.ENotificationImpl;
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
+ * </p>
* <ul>
* <li>{@link org.eclipse.emf.compare.tests.nodes.impl.NodeSingleValueReferenceImpl#getSingleValuedReference <em>Single Valued Reference</em>}</li>
* </ul>
- * </p>
*
* @generated
*/
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesFactoryImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesFactoryImpl.java
index f0d415e97..c59ce298e 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesFactoryImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesFactoryImpl.java
@@ -77,6 +77,7 @@ public class NodesFactoryImpl extends EFactoryImpl implements NodesFactory {
case NodesPackage.NODE_SINGLE_VALUE_CONTAINMENT: return createNodeSingleValueContainment();
case NodesPackage.NODE_SINGLE_VALUE_ATTRIBUTE: return createNodeSingleValueAttribute();
case NodesPackage.NODE_MULTI_VALUED_ATTRIBUTE: return createNodeMultiValuedAttribute();
+ case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE: return createNodeMultiValuedNonUniqueAttribute();
case NodesPackage.NODE_SINGLE_VALUE_REFERENCE: return createNodeSingleValueReference();
case NodesPackage.NODE_MULTI_VALUE_REFERENCE: return createNodeMultiValueReference();
case NodesPackage.NODE_OPPOSITE_REF_ONE_TO_ONE: return createNodeOppositeRefOneToOne();
@@ -177,6 +178,16 @@ public class NodesFactoryImpl extends EFactoryImpl implements NodesFactory {
* <!-- end-user-doc -->
* @generated
*/
+ public NodeMultiValuedNonUniqueAttribute createNodeMultiValuedNonUniqueAttribute() {
+ NodeMultiValuedNonUniqueAttributeImpl nodeMultiValuedNonUniqueAttribute = new NodeMultiValuedNonUniqueAttributeImpl();
+ return nodeMultiValuedNonUniqueAttribute;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
public NodeSingleValueReference createNodeSingleValueReference() {
NodeSingleValueReferenceImpl nodeSingleValueReference = new NodeSingleValueReferenceImpl();
return nodeSingleValueReference;
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesPackageImpl.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesPackageImpl.java
index a081f749e..48f3eaf92 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesPackageImpl.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/impl/NodesPackageImpl.java
@@ -18,6 +18,7 @@ import org.eclipse.emf.compare.tests.nodes.NodeFeatureMapNonContainment;
import org.eclipse.emf.compare.tests.nodes.NodeMultiValueEEnumAttribute;
import org.eclipse.emf.compare.tests.nodes.NodeMultiValueReference;
import org.eclipse.emf.compare.tests.nodes.NodeMultiValuedAttribute;
+import org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute;
import org.eclipse.emf.compare.tests.nodes.NodeMultipleContainment;
import org.eclipse.emf.compare.tests.nodes.NodeOppositeRefManyToMany;
import org.eclipse.emf.compare.tests.nodes.NodeOppositeRefOneToMany;
@@ -91,6 +92,13 @@ public class NodesPackageImpl extends EPackageImpl implements NodesPackage {
* <!-- end-user-doc -->
* @generated
*/
+ private EClass nodeMultiValuedNonUniqueAttributeEClass = null;
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
private EClass nodeSingleValueReferenceEClass = null;
/**
@@ -337,6 +345,24 @@ public class NodesPackageImpl extends EPackageImpl implements NodesPackage {
* <!-- end-user-doc -->
* @generated
*/
+ public EClass getNodeMultiValuedNonUniqueAttribute() {
+ return nodeMultiValuedNonUniqueAttributeEClass;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ public EAttribute getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute() {
+ return (EAttribute)nodeMultiValuedNonUniqueAttributeEClass.getEStructuralFeatures().get(0);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
public EClass getNodeSingleValueReference() {
return nodeSingleValueReferenceEClass;
}
@@ -647,6 +673,9 @@ public class NodesPackageImpl extends EPackageImpl implements NodesPackage {
nodeMultiValuedAttributeEClass = createEClass(NODE_MULTI_VALUED_ATTRIBUTE);
createEAttribute(nodeMultiValuedAttributeEClass, NODE_MULTI_VALUED_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE);
+ nodeMultiValuedNonUniqueAttributeEClass = createEClass(NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE);
+ createEAttribute(nodeMultiValuedNonUniqueAttributeEClass, NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE__MULTI_VALUED_ATTRIBUTE);
+
nodeSingleValueReferenceEClass = createEClass(NODE_SINGLE_VALUE_REFERENCE);
createEReference(nodeSingleValueReferenceEClass, NODE_SINGLE_VALUE_REFERENCE__SINGLE_VALUED_REFERENCE);
@@ -722,6 +751,7 @@ public class NodesPackageImpl extends EPackageImpl implements NodesPackage {
nodeSingleValueContainmentEClass.getESuperTypes().add(this.getNode());
nodeSingleValueAttributeEClass.getESuperTypes().add(this.getNode());
nodeMultiValuedAttributeEClass.getESuperTypes().add(this.getNode());
+ nodeMultiValuedNonUniqueAttributeEClass.getESuperTypes().add(this.getNode());
nodeSingleValueReferenceEClass.getESuperTypes().add(this.getNode());
nodeMultiValueReferenceEClass.getESuperTypes().add(this.getNode());
nodeOppositeRefOneToOneEClass.getESuperTypes().add(this.getNode());
@@ -751,6 +781,9 @@ public class NodesPackageImpl extends EPackageImpl implements NodesPackage {
initEClass(nodeMultiValuedAttributeEClass, NodeMultiValuedAttribute.class, "NodeMultiValuedAttribute", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
initEAttribute(getNodeMultiValuedAttribute_MultiValuedAttribute(), ecorePackage.getEString(), "multiValuedAttribute", null, 0, -1, NodeMultiValuedAttribute.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); //$NON-NLS-1$
+ initEClass(nodeMultiValuedNonUniqueAttributeEClass, NodeMultiValuedNonUniqueAttribute.class, "NodeMultiValuedNonUniqueAttribute", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
+ initEAttribute(getNodeMultiValuedNonUniqueAttribute_MultiValuedAttribute(), ecorePackage.getEString(), "multiValuedAttribute", null, 0, -1, NodeMultiValuedNonUniqueAttribute.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, !IS_UNIQUE, !IS_DERIVED, IS_ORDERED); //$NON-NLS-1$
+
initEClass(nodeSingleValueReferenceEClass, NodeSingleValueReference.class, "NodeSingleValueReference", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
initEReference(getNodeSingleValueReference_SingleValuedReference(), this.getNode(), null, "singleValuedReference", null, 0, 1, NodeSingleValueReference.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); //$NON-NLS-1$
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesAdapterFactory.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesAdapterFactory.java
index 7f5d97b14..612e266a7 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesAdapterFactory.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesAdapterFactory.java
@@ -103,6 +103,10 @@ public class NodesAdapterFactory extends AdapterFactoryImpl {
return createNodeMultiValuedAttributeAdapter();
}
@Override
+ public Adapter caseNodeMultiValuedNonUniqueAttribute(NodeMultiValuedNonUniqueAttribute object) {
+ return createNodeMultiValuedNonUniqueAttributeAdapter();
+ }
+ @Override
public Adapter caseNodeSingleValueReference(NodeSingleValueReference object) {
return createNodeSingleValueReferenceAdapter();
}
@@ -233,6 +237,20 @@ public class NodesAdapterFactory extends AdapterFactoryImpl {
}
/**
+ * Creates a new adapter for an object of class '{@link org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute <em>Node Multi Valued Non Unique Attribute</em>}'.
+ * <!-- begin-user-doc -->
+ * This default implementation returns null so that we can easily ignore cases;
+ * it's useful to ignore a case when inheritance will catch all the cases anyway.
+ * <!-- end-user-doc -->
+ * @return the new adapter.
+ * @see org.eclipse.emf.compare.tests.nodes.NodeMultiValuedNonUniqueAttribute
+ * @generated
+ */
+ public Adapter createNodeMultiValuedNonUniqueAttributeAdapter() {
+ return null;
+ }
+
+ /**
* Creates a new adapter for an object of class '{@link org.eclipse.emf.compare.tests.nodes.NodeSingleValueReference <em>Node Single Value Reference</em>}'.
* <!-- begin-user-doc -->
* This default implementation returns null so that we can easily ignore cases;
diff --git a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesSwitch.java b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesSwitch.java
index 183d91976..6b8ea51f4 100644
--- a/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesSwitch.java
+++ b/plugins/org.eclipse.emf.compare.tests/src-gen/org/eclipse/emf/compare/tests/nodes/util/NodesSwitch.java
@@ -132,6 +132,13 @@ public class NodesSwitch<T> {
if (result == null) result = defaultCase(theEObject);
return result;
}
+ case NodesPackage.NODE_MULTI_VALUED_NON_UNIQUE_ATTRIBUTE: {
+ NodeMultiValuedNonUniqueAttribute nodeMultiValuedNonUniqueAttribute = (NodeMultiValuedNonUniqueAttribute)theEObject;
+ T result = caseNodeMultiValuedNonUniqueAttribute(nodeMultiValuedNonUniqueAttribute);
+ if (result == null) result = caseNode(nodeMultiValuedNonUniqueAttribute);
+ if (result == null) result = defaultCase(theEObject);
+ return result;
+ }
case NodesPackage.NODE_SINGLE_VALUE_REFERENCE: {
NodeSingleValueReference nodeSingleValueReference = (NodeSingleValueReference)theEObject;
T result = caseNodeSingleValueReference(nodeSingleValueReference);
@@ -282,6 +289,21 @@ public class NodesSwitch<T> {
}
/**
+ * Returns the result of interpreting the object as an instance of '<em>Node Multi Valued Non Unique Attribute</em>'.
+ * <!-- begin-user-doc -->
+ * This implementation returns null;
+ * returning a non-null result will terminate the switch.
+ * <!-- end-user-doc -->
+ * @param object the target of the switch.
+ * @return the result of interpreting the object as an instance of '<em>Node Multi Valued Non Unique Attribute</em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseNodeMultiValuedNonUniqueAttribute(NodeMultiValuedNonUniqueAttribute object) {
+ return null;
+ }
+
+ /**
* Returns the result of interpreting the object as an instance of '<em>Node Single Value Reference</em>'.
* <!-- begin-user-doc -->
* This implementation returns null;
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/NonUniqueMultiValuedAttributeTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/NonUniqueMultiValuedAttributeTest.java
new file mode 100644
index 000000000..58abb9e36
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/NonUniqueMultiValuedAttributeTest.java
@@ -0,0 +1,600 @@
+/*******************************************************************************
+ * Copyright (c) 2019 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:
+ * Laurent Goubet - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.tests.diff;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.emf.common.util.BasicMonitor;
+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;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.EMFCompare;
+import org.eclipse.emf.compare.merge.IMerger;
+import org.eclipse.emf.compare.scope.DefaultComparisonScope;
+import org.eclipse.emf.compare.scope.IComparisonScope;
+import org.eclipse.emf.compare.tests.diff.data.nonuniquemultivaluedattribute.NonUniqueMultiValuedAttributeInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.junit.Test;
+
+/*
+ * non-unique multi-valued attributes may contain duplicate values and thus present particularities for
+ * both the differencing process and the conflict detection process. During detection, we need to consider
+ * that a if one side has two identical values and the other has three, then there is an addition (and not
+ * a move has was previously detected). Furthermore, we will consider that adding the same value on both
+ * sides of a three-way comparison is a pseudo-conflict (previously, there was no conflict at all since
+ * non-unique values can have the same value more than once and thus the merge of such differences could
+ * be done without issues). The comparison path for 3-way and 2-way being different, we need to make sure
+ * both situations are tested.
+ */
+@SuppressWarnings("nls")
+public class NonUniqueMultiValuedAttributeTest {
+ private NonUniqueMultiValuedAttributeInputData input = new NonUniqueMultiValuedAttributeInputData();
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseA3WayDiff() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+ Resource origin = input.getNonUniqueMultiValuedAttributeCaseAOrigin();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+ Diff diff1 = differences.get(0); // ADD 3.03030303E-4
+ Diff diff2 = differences.get(1); // ADD 0.0
+ Diff diff3 = differences.get(2); // DELETE 1.69714
+ Diff diff4 = differences.get(3); // DELETE 5.985E-4
+
+ assertTrue(diff1 instanceof AttributeChange);
+ assertTrue(diff2 instanceof AttributeChange);
+ assertTrue(diff3 instanceof AttributeChange);
+ assertTrue(diff4 instanceof AttributeChange);
+ assertEquals("3.03030303E-4", ((AttributeChange)diff1).getValue());
+ assertEquals("0.0", ((AttributeChange)diff2).getValue());
+ assertEquals("1.69714", ((AttributeChange)diff3).getValue());
+ assertEquals("5.985E-4", ((AttributeChange)diff4).getValue());
+ assertEquals(DifferenceKind.ADD, diff1.getKind());
+ assertEquals(DifferenceKind.ADD, diff2.getKind());
+ assertEquals(DifferenceKind.DELETE, diff3.getKind());
+ assertEquals(DifferenceKind.DELETE, diff4.getKind());
+ assertEquals(DifferenceSource.RIGHT, diff1.getSource());
+ assertEquals(DifferenceSource.RIGHT, diff2.getSource());
+ assertEquals(DifferenceSource.RIGHT, diff3.getSource());
+ assertEquals(DifferenceSource.RIGHT, diff4.getSource());
+
+ // No conflicts
+ assertTrue(comparison.getConflicts().isEmpty());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseA2WayDiff() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+ Diff diff1 = differences.get(0); // ADD 1.69714
+ Diff diff2 = differences.get(1); // ADD 5.985E-4
+ Diff diff3 = differences.get(2); // DELETE 3.03030303E-4
+ Diff diff4 = differences.get(3); // DELETE 0.0
+
+ assertTrue(diff1 instanceof AttributeChange);
+ assertTrue(diff2 instanceof AttributeChange);
+ assertTrue(diff3 instanceof AttributeChange);
+ assertTrue(diff4 instanceof AttributeChange);
+ assertEquals("1.69714", ((AttributeChange)diff1).getValue());
+ assertEquals("5.985E-4", ((AttributeChange)diff2).getValue());
+ assertEquals("3.03030303E-4", ((AttributeChange)diff3).getValue());
+ assertEquals("0.0", ((AttributeChange)diff4).getValue());
+ assertEquals(DifferenceKind.ADD, diff1.getKind());
+ assertEquals(DifferenceKind.ADD, diff2.getKind());
+ assertEquals(DifferenceKind.DELETE, diff3.getKind());
+ assertEquals(DifferenceKind.DELETE, diff4.getKind());
+ assertEquals(DifferenceSource.LEFT, diff1.getSource());
+ assertEquals(DifferenceSource.LEFT, diff2.getSource());
+ assertEquals(DifferenceSource.LEFT, diff3.getSource());
+ assertEquals(DifferenceSource.LEFT, diff4.getSource());
+
+ // No conflicts
+ assertTrue(comparison.getConflicts().isEmpty());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseA3WayMergeRtL() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+ Resource origin = input.getNonUniqueMultiValuedAttributeCaseAOrigin();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseA3WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have 8 differences, paired in 4 pseudo-conflicts
+ assertEquals(8, comparison.getDifferences().size());
+ assertEquals(4, comparison.getConflicts().size());
+
+ for (Conflict c : comparison.getConflicts()) {
+ assertEquals(2, c.getDifferences().size());
+ assertEquals(ConflictKind.PSEUDO, c.getKind());
+ }
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseA2WayMergeRtL() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseA2WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have no differences left
+ assertEquals(0, comparison.getDifferences().size());
+ assertEquals(0, comparison.getConflicts().size());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseA3WayMergeLtR() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+ Resource origin = input.getNonUniqueMultiValuedAttributeCaseAOrigin();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseA3WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have 0 differences
+ // (all diffs were on the right side so we cancelled them by merging)
+ assertTrue(comparison.getDifferences().isEmpty());
+ assertTrue(comparison.getConflicts().isEmpty());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseA2WayMergeLtR() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseALeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseARight();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseA2WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have no differences left
+ assertEquals(0, comparison.getDifferences().size());
+ assertEquals(0, comparison.getConflicts().size());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseB3WayDiff() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+ Resource origin = input.getNonUniqueMultiValuedAttributeCaseBOrigin();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 3 differences
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(3, differences.size());
+ Diff diff1 = differences.get(0); // MOVE a
+ Diff diff2 = differences.get(1); // ADD a
+ Diff diff3 = differences.get(2); // DELETE b
+
+ assertTrue(diff1 instanceof AttributeChange);
+ assertTrue(diff2 instanceof AttributeChange);
+ assertTrue(diff3 instanceof AttributeChange);
+ assertEquals("a", ((AttributeChange)diff1).getValue());
+ assertEquals("a", ((AttributeChange)diff2).getValue());
+ assertEquals("b", ((AttributeChange)diff3).getValue());
+ assertEquals(DifferenceKind.MOVE, diff1.getKind());
+ assertEquals(DifferenceKind.ADD, diff2.getKind());
+ assertEquals(DifferenceKind.DELETE, diff3.getKind());
+ assertEquals(DifferenceSource.RIGHT, diff1.getSource());
+ assertEquals(DifferenceSource.RIGHT, diff2.getSource());
+ assertEquals(DifferenceSource.RIGHT, diff3.getSource());
+
+ // No conflicts
+ assertTrue(comparison.getConflicts().isEmpty());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseB2WayDiff() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 3 differences
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(3, differences.size());
+ Diff diff1 = differences.get(0); // MOVE b
+ Diff diff2 = differences.get(1); // MOVE d
+ Diff diff3 = differences.get(2); // DELETE a
+
+ assertTrue(diff1 instanceof AttributeChange);
+ assertTrue(diff2 instanceof AttributeChange);
+ assertTrue(diff3 instanceof AttributeChange);
+ assertEquals("b", ((AttributeChange)diff1).getValue());
+ assertEquals("d", ((AttributeChange)diff2).getValue());
+ assertEquals("a", ((AttributeChange)diff3).getValue());
+ assertEquals(DifferenceKind.ADD, diff1.getKind());
+ assertEquals(DifferenceKind.MOVE, diff2.getKind());
+ assertEquals(DifferenceKind.DELETE, diff3.getKind());
+ assertEquals(DifferenceSource.LEFT, diff1.getSource());
+ assertEquals(DifferenceSource.LEFT, diff2.getSource());
+ assertEquals(DifferenceSource.LEFT, diff3.getSource());
+
+ // No conflicts
+ assertTrue(comparison.getConflicts().isEmpty());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseB3WayMergeRtL() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+ Resource origin = input.getNonUniqueMultiValuedAttributeCaseBOrigin();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 3 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseB3WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(3, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have 6 differences, paired in 3 pseudo-conflicts
+ assertEquals(6, comparison.getDifferences().size());
+ assertEquals(3, comparison.getConflicts().size());
+
+ for (Conflict c : comparison.getConflicts()) {
+ assertEquals(2, c.getDifferences().size());
+ assertEquals(ConflictKind.PSEUDO, c.getKind());
+ }
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseB2WayMergeRtL() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 3 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseB2WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(3, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have no differences left
+ assertEquals(0, comparison.getDifferences().size());
+ assertEquals(0, comparison.getConflicts().size());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseB3WayMergeLtR() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+ Resource origin = input.getNonUniqueMultiValuedAttributeCaseBOrigin();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 3 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseB3WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(3, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have 0 differences
+ // (all diffs were on the right side so we cancelled them by merging)
+ assertTrue(comparison.getDifferences().isEmpty());
+ assertTrue(comparison.getConflicts().isEmpty());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseB2WayMergeLtR() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseBLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseBRight();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 3 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseB2WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(3, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have no differences left
+ assertEquals(0, comparison.getDifferences().size());
+ assertEquals(0, comparison.getConflicts().size());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseC3WayDiff() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+ Resource origin = input.getNonUniqueMultiValuedAttributeCaseCOrigin();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+ Diff diff1 = differences.get(0); // ADD c
+ Diff diff2 = differences.get(1); // ADD b
+ Diff diff3 = differences.get(2); // ADD b
+ Diff diff4 = differences.get(3); // MOVE d
+
+ assertTrue(diff1 instanceof AttributeChange);
+ assertTrue(diff2 instanceof AttributeChange);
+ assertTrue(diff3 instanceof AttributeChange);
+ assertTrue(diff4 instanceof AttributeChange);
+ assertEquals("c", ((AttributeChange)diff1).getValue());
+ assertEquals("b", ((AttributeChange)diff2).getValue());
+ assertEquals("b", ((AttributeChange)diff3).getValue());
+ assertEquals("d", ((AttributeChange)diff4).getValue());
+ assertEquals(DifferenceKind.ADD, diff1.getKind());
+ assertEquals(DifferenceKind.ADD, diff2.getKind());
+ assertEquals(DifferenceKind.ADD, diff3.getKind());
+ assertEquals(DifferenceKind.MOVE, diff4.getKind());
+ assertEquals(DifferenceSource.LEFT, diff1.getSource());
+ assertEquals(DifferenceSource.LEFT, diff2.getSource());
+ assertEquals(DifferenceSource.LEFT, diff3.getSource());
+ assertEquals(DifferenceSource.LEFT, diff4.getSource());
+
+ // No conflicts
+ assertTrue(comparison.getConflicts().isEmpty());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseC2WayDiff() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+ Diff diff1 = differences.get(0); // ADD c
+ Diff diff2 = differences.get(1); // ADD b
+ Diff diff3 = differences.get(2); // ADD b
+ Diff diff4 = differences.get(3); // MOVE d
+
+ assertTrue(diff1 instanceof AttributeChange);
+ assertTrue(diff2 instanceof AttributeChange);
+ assertTrue(diff3 instanceof AttributeChange);
+ assertTrue(diff4 instanceof AttributeChange);
+ assertEquals("c", ((AttributeChange)diff1).getValue());
+ assertEquals("b", ((AttributeChange)diff2).getValue());
+ assertEquals("b", ((AttributeChange)diff3).getValue());
+ assertEquals("d", ((AttributeChange)diff4).getValue());
+ assertEquals(DifferenceKind.ADD, diff1.getKind());
+ assertEquals(DifferenceKind.ADD, diff2.getKind());
+ assertEquals(DifferenceKind.ADD, diff3.getKind());
+ assertEquals(DifferenceKind.MOVE, diff4.getKind());
+ assertEquals(DifferenceSource.LEFT, diff1.getSource());
+ assertEquals(DifferenceSource.LEFT, diff2.getSource());
+ assertEquals(DifferenceSource.LEFT, diff3.getSource());
+ assertEquals(DifferenceSource.LEFT, diff4.getSource());
+
+ // No conflicts
+ assertTrue(comparison.getConflicts().isEmpty());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseC3WayMergeRtL() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+ Resource origin = input.getNonUniqueMultiValuedAttributeCaseCOrigin();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseC3WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have 0 differences
+ // (all diffs were on the left side so we cancelled them by merging)
+ assertTrue(comparison.getDifferences().isEmpty());
+ assertTrue(comparison.getConflicts().isEmpty());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseC2WayMergeRtL() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseC2WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyRightToLeft(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have no differences left
+ assertEquals(0, comparison.getDifferences().size());
+ assertEquals(0, comparison.getConflicts().size());
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseC3WayMergeLtR() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+ Resource origin = input.getNonUniqueMultiValuedAttributeCaseCOrigin();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseC3WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have 8 differences, paired in 4 pseudo-conflicts
+ assertEquals(8, comparison.getDifferences().size());
+ assertEquals(4, comparison.getConflicts().size());
+
+ for (Conflict c : comparison.getConflicts()) {
+ assertEquals(2, c.getDifferences().size());
+ assertEquals(ConflictKind.PSEUDO, c.getKind());
+ }
+ }
+
+ @Test
+ public void testNonUniqueMultiValuedAttributeCaseC2WayMergeLtR() throws IOException {
+ Resource left = input.getNonUniqueMultiValuedAttributeCaseCLeft();
+ Resource right = input.getNonUniqueMultiValuedAttributeCaseCRight();
+
+ IComparisonScope scope = new DefaultComparisonScope(left, right, null);
+ Comparison comparison = EMFCompare.builder().build().compare(scope);
+
+ // We expect 4 differences and no conflict.
+ // see testNonUniqueMultiValuedAttributeCaseC2WayDiff if this fails
+ assertTrue(comparison.getConflicts().isEmpty());
+ List<Diff> differences = comparison.getDifferences();
+ assertEquals(4, differences.size());
+
+ IMerger.Registry mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
+ for (Diff diff : differences) {
+ mergerRegistry.getHighestRankingMerger(diff).copyLeftToRight(diff,
+ BasicMonitor.toMonitor(new NullProgressMonitor()));
+ }
+
+ comparison = EMFCompare.builder().build().compare(scope);
+ // we should now have no differences left
+ assertEquals(0, comparison.getDifferences().size());
+ assertEquals(0, comparison.getConflicts().size());
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/SingleValuedAttributePseudoConflictTest.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/SingleValuedAttributePseudoConflictTest.java
index 20b610c8e..928924194 100644
--- a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/SingleValuedAttributePseudoConflictTest.java
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/SingleValuedAttributePseudoConflictTest.java
@@ -42,7 +42,7 @@ public class SingleValuedAttributePseudoConflictTest {
Resource right = input.getSingleValueAttributePseudoConflictRight();
Resource origin = input.getSingleValueAttributePseudoConflictOrigin();
- IComparisonScope scope = new DefaultComparisonScope(right, left, origin);
+ IComparisonScope scope = new DefaultComparisonScope(left, right, origin);
Comparison comparison = EMFCompare.builder().build().compare(scope);
// There are only two differences
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/NonUniqueMultiValuedAttributeInputData.java b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/NonUniqueMultiValuedAttributeInputData.java
new file mode 100644
index 000000000..beb1e8009
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/NonUniqueMultiValuedAttributeInputData.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2019 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:
+ * Laurent Goubet - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.tests.diff.data.nonuniquemultivaluedattribute;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.tests.framework.AbstractInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+
+@SuppressWarnings("nls")
+public class NonUniqueMultiValuedAttributeInputData extends AbstractInputData {
+ public Resource getNonUniqueMultiValuedAttributeCaseALeft() throws IOException {
+ return loadFromClassLoader("a/left.nodes");
+ }
+
+ public Resource getNonUniqueMultiValuedAttributeCaseARight() throws IOException {
+ return loadFromClassLoader("a/right.nodes");
+ }
+
+ public Resource getNonUniqueMultiValuedAttributeCaseAOrigin() throws IOException {
+ return loadFromClassLoader("a/origin.nodes");
+ }
+
+ public Resource getNonUniqueMultiValuedAttributeCaseBLeft() throws IOException {
+ return loadFromClassLoader("b/left.nodes");
+ }
+
+ public Resource getNonUniqueMultiValuedAttributeCaseBRight() throws IOException {
+ return loadFromClassLoader("b/right.nodes");
+ }
+
+ public Resource getNonUniqueMultiValuedAttributeCaseBOrigin() throws IOException {
+ return loadFromClassLoader("b/origin.nodes");
+ }
+
+ public Resource getNonUniqueMultiValuedAttributeCaseCLeft() throws IOException {
+ return loadFromClassLoader("c/left.nodes");
+ }
+
+ public Resource getNonUniqueMultiValuedAttributeCaseCRight() throws IOException {
+ return loadFromClassLoader("c/right.nodes");
+ }
+
+ public Resource getNonUniqueMultiValuedAttributeCaseCOrigin() throws IOException {
+ return loadFromClassLoader("c/origin.nodes");
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/left.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/left.nodes
new file mode 100644
index 000000000..f568a018d
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/left.nodes
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">
+ <multiValuedAttribute>1.69714</multiValuedAttribute>
+ <multiValuedAttribute>5.985E-4</multiValuedAttribute>
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+</nodes:NodeMultiValuedNonUniqueAttribute>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/origin.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/origin.nodes
new file mode 100644
index 000000000..f568a018d
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/origin.nodes
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">
+ <multiValuedAttribute>1.69714</multiValuedAttribute>
+ <multiValuedAttribute>5.985E-4</multiValuedAttribute>
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+</nodes:NodeMultiValuedNonUniqueAttribute>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/right.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/right.nodes
new file mode 100644
index 000000000..54c3ee361
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/a/right.nodes
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+ <multiValuedAttribute>3.03030303E-4</multiValuedAttribute>
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+ <multiValuedAttribute>0.0</multiValuedAttribute>
+</nodes:NodeMultiValuedNonUniqueAttribute>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/left.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/left.nodes
new file mode 100644
index 000000000..c57e03a20
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/left.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>c</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>d</multiValuedAttribute>
+</nodes:NodeMultiValuedNonUniqueAttribute>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/origin.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/origin.nodes
new file mode 100644
index 000000000..c57e03a20
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/origin.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>c</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>d</multiValuedAttribute>
+</nodes:NodeMultiValuedNonUniqueAttribute>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/right.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/right.nodes
new file mode 100644
index 000000000..3a9edcfe1
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/b/right.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>c</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>d</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+</nodes:NodeMultiValuedNonUniqueAttribute>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/left.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/left.nodes
new file mode 100644
index 000000000..a4c319404
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/left.nodes
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">
+ <multiValuedAttribute>c</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>d</multiValuedAttribute>
+</nodes:NodeMultiValuedNonUniqueAttribute>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/origin.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/origin.nodes
new file mode 100644
index 000000000..35cd66986
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/origin.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>d</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+</nodes:NodeMultiValuedNonUniqueAttribute>
diff --git a/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/right.nodes b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/right.nodes
new file mode 100644
index 000000000..35cd66986
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.tests/src/org/eclipse/emf/compare/tests/diff/data/nonuniquemultivaluedattribute/c/right.nodes
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<nodes:NodeMultiValuedNonUniqueAttribute xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:nodes="http://www.eclipse.org/emf/compare/tests/nodes" xmi:id="_Y7T9MMQPEemKOdaA3QMhmg" name="root">
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>b</multiValuedAttribute>
+ <multiValuedAttribute>d</multiValuedAttribute>
+ <multiValuedAttribute>a</multiValuedAttribute>
+</nodes:NodeMultiValuedNonUniqueAttribute>
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 2ecd6fa88..1290f4a28 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
@@ -28,6 +28,8 @@ import org.eclipse.emf.compare.tests.diff.DiffUtilTest;
import org.eclipse.emf.compare.tests.diff.FeatureFilterTest;
import org.eclipse.emf.compare.tests.diff.FeatureMapMoveDiffTest;
import org.eclipse.emf.compare.tests.diff.LCSPerformanceTest;
+import org.eclipse.emf.compare.tests.diff.NonUniqueMultiValuedAttributeTest;
+import org.eclipse.emf.compare.tests.diff.SingleValuedAttributePseudoConflictTest;
import org.eclipse.emf.compare.tests.diff.ThreeWayTextDiffTest;
import org.eclipse.emf.compare.tests.diff.URIDistanceTest;
import org.eclipse.emf.compare.tests.edit.AllEditTests;
@@ -106,7 +108,8 @@ import org.junit.runners.Suite.SuiteClasses;
RankedAdapterFactoryRegistryTest.class, ComparisonScopeAdapterTest.class,
EMFComparePredicatesTest.class, ImplicationsMergeTest.class, GraphTest.class,
ConflictImplicationsTest_Bug484579.class, PseudoConflictDetectionTest.class, ComplexMergeTest.class,
- ConflictSearchTest.class, DiffRelationshipComputerTest.class })
+ ConflictSearchTest.class, DiffRelationshipComputerTest.class,
+ SingleValuedAttributePseudoConflictTest.class, NonUniqueMultiValuedAttributeTest.class, })
public class AllTests {
@BeforeClass
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 38c2b6293..38d930562 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
@@ -464,16 +464,7 @@ public class DefaultConflictDetector implements IConflictDetector {
final IEqualityHelper equalityHelper = comparison.getEqualityHelper();
for (Diff candidate : refinedCandidates) {
- final Object candidateValue;
- if (candidate instanceof ReferenceChange) {
- candidateValue = ((ReferenceChange)candidate).getValue();
- } else if (candidate instanceof AttributeChange) {
- candidateValue = ((AttributeChange)candidate).getValue();
- } else if (candidate instanceof FeatureMapChange) {
- candidateValue = ((FeatureMap.Entry)((FeatureMapChange)candidate).getValue()).getValue();
- } else {
- candidateValue = null;
- }
+ final Object candidateValue = getDiffValue(candidate);
if (diff.getMatch() == candidate.getMatch()) {
if (equalityHelper.matchingValues(changedValue, candidateValue)) {
@@ -655,16 +646,7 @@ public class DefaultConflictDetector implements IConflictDetector {
});
for (Diff candidate : refinedCandidates) {
- final Object candidateValue;
- if (candidate instanceof ReferenceChange) {
- candidateValue = ((ReferenceChange)candidate).getValue();
- } else if (candidate instanceof AttributeChange) {
- candidateValue = ((AttributeChange)candidate).getValue();
- } else if (candidate instanceof FeatureMapChange) {
- candidateValue = ((FeatureMap.Entry)((FeatureMapChange)candidate).getValue()).getValue();
- } else {
- candidateValue = null;
- }
+ final Object candidateValue = getDiffValue(candidate);
if (diff.getMatch() == candidate.getMatch()
&& comparison.getEqualityHelper().matchingValues(changedValue, candidateValue)) {
@@ -732,16 +714,7 @@ public class DefaultConflictDetector implements IConflictDetector {
});
for (Diff candidate : refinedCandidates) {
- final Object movedValue;
- if (candidate instanceof ReferenceChange) {
- movedValue = ((ReferenceChange)candidate).getValue();
- } else if (candidate instanceof AttributeChange) {
- movedValue = ((AttributeChange)candidate).getValue();
- } else if (candidate instanceof FeatureMapChange) {
- movedValue = ((FeatureMap.Entry)((FeatureMapChange)candidate).getValue()).getValue();
- } else {
- movedValue = null;
- }
+ final Object movedValue = getDiffValue(candidate);
if (comparison.getEqualityHelper().matchingValues(deletedValue, movedValue)) {
if (candidate.getKind() == DifferenceKind.MOVE) {
@@ -808,17 +781,15 @@ public class DefaultConflictDetector implements IConflictDetector {
});
for (Diff candidate : refinedCandidates) {
- final Object candidateValue;
- if (candidate instanceof ReferenceChange) {
- candidateValue = ((ReferenceChange)candidate).getValue();
- } else if (candidate instanceof AttributeChange) {
- candidateValue = ((AttributeChange)candidate).getValue();
- } else if (candidate instanceof FeatureMapChange) {
- candidateValue = ((FeatureMap.Entry)((FeatureMapChange)candidate).getValue()).getValue();
- } else {
- candidateValue = null;
- }
- // No diff on non unique features : multiple same values can coexist
+ final Object candidateValue = getDiffValue(candidate);
+ /*
+ * multiple same values can coexist on non-unique features, so we won't detect real conflicts in
+ * such cases. However, if a value is not present in the origin but added in both left and right,
+ * we'll consider it a pseudo conflict to avoid "noise" for the user. If the same value has been
+ * added multiple times on the side(s), we'll only detect pseudo conflict on pairs of additions
+ * and none if there is no longer a pair (i.e. the same value has been added one more times on one
+ * side than in the other).
+ */
if (feature.isUnique()
&& comparison.getEqualityHelper().matchingValues(addedValue, candidateValue)) {
// This is a conflict. Is it real?
@@ -840,10 +811,53 @@ public class DefaultConflictDetector implements IConflictDetector {
} else {
conflictOn(comparison, diff, candidate, ConflictKind.REAL);
}
+ } else if (!feature.isUnique()) {
+ if (comparison.getEqualityHelper().matchingValues(addedValue, candidateValue)) {
+ // potential pseudo-conflict
+ // Is this candidate already paired in a pseudo conflict?
+ if (candidate.getConflict() != null
+ && candidate.getConflict().getKind() == ConflictKind.PSEUDO) {
+ if (candidate.getConflict().getDifferences().stream()
+ .anyMatch(conflictingWith -> matchingConflictingDiff(comparison, diff,
+ conflictingWith))) {
+ // continue to next candidate
+ continue;
+ }
+ }
+ // Even if these two values haven't been added at the same index on both side, we'll
+ // consider it a pseudo-conflict.
+ conflictOn(comparison, diff, candidate, ConflictKind.PSEUDO);
+ }
}
}
}
+ private static boolean matchingConflictingDiff(Comparison comparison, Diff reference, Diff candidate) {
+ if (reference == candidate) {
+ return true;
+ }
+ if (reference.getMatch() == candidate.getMatch() && reference.getKind() == candidate.getKind()) {
+ Object referenceValue = getDiffValue(reference);
+ Object candidateValue = getDiffValue(candidate);
+ return comparison.getEqualityHelper().matchingValues(referenceValue, candidateValue);
+ }
+ return false;
+ }
+
+ private static Object getDiffValue(Diff diff) {
+ Object value;
+ if (diff instanceof ReferenceChange) {
+ value = ((ReferenceChange)diff).getValue();
+ } else if (diff instanceof AttributeChange) {
+ value = ((AttributeChange)diff).getValue();
+ } else if (diff instanceof FeatureMapChange) {
+ value = ((FeatureMap.Entry)((FeatureMapChange)diff).getValue()).getValue();
+ } else {
+ value = null;
+ }
+ return value;
+ }
+
/**
* This will be called once for each ResourceAttachmentChange in the comparison model.
*
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java
index de5c61b59..d9f4c114b 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/diff/DefaultDiffEngine.java
@@ -86,27 +86,29 @@ public class DefaultDiffEngine implements IDiffEngine {
}
/**
- * Checks whether the given {@code iterable} contains the given {@code element} according to the semantics
- * of {@link IEqualityHelper#matchingValues(Comparison, Object, Object)}.
+ * Checks whether the given {@code list} contains the given {@code element} according to the semantics of
+ * {@link IEqualityHelper#matchingValues(Comparison, Object, Object)} and returns the index at which it is
+ * positioned if applicable.
*
* @param comparison
* This will be used in order to retrieve the Match for EObjects when comparing them.
- * @param iterable
- * Iterable which content we are to check.
+ * @param list
+ * List which content we are to check.
* @param element
- * The element we expect to be contained in {@code iterable}.
+ * The element we expect to be contained in {@code list}.
* @param <E>
* Type of the input iterable's content.
- * @return {@code true} if the given {@code iterable} contains {@code element}, {@code false} otherwise.
+ * @return The index at which the given {@code list} contains {@code element}, {@code -1} otherwise.
*/
- protected <E> boolean contains(Comparison comparison, Iterable<E> iterable, E element) {
+ protected <E> int indexOf(Comparison comparison, List<E> list, E element) {
final IEqualityHelper equality = comparison.getEqualityHelper();
- for (E candidate : iterable) {
+ for (int i = 0; i < list.size(); i++) {
+ E candidate = list.get(i);
if (equality.matchingValues(candidate, element)) {
- return true;
+ return i;
}
}
- return false;
+ return -1;
}
/**
@@ -779,6 +781,7 @@ public class DefaultDiffEngine implements IDiffEngine {
// Any value that is _not_ in the LCS has changed.
+ List<Object> originWithNoLCS = trimLCS(originValues, lcsOriginLeft, equality);
int lcsCursor = 0;
Optional<Object> lcsCurrent = getIfPresent(lcsOriginLeft, lcsCursor);
for (Object diffCandidate : leftValues) {
@@ -789,12 +792,15 @@ public class DefaultDiffEngine implements IDiffEngine {
continue;
}
- if (contains(comparison, originValues, diffCandidate)) {
+ int index = indexOf(comparison, originWithNoLCS, diffCandidate);
+ if (index >= 0) {
+ originWithNoLCS.remove(index);
if (checkOrdering) {
featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.LEFT);
}
} else if (FeatureMapUtil.isFeatureMap(feature) && diffCandidate instanceof FeatureMap.Entry) {
- // A value of a FeatureMap changed his key
+ // A value of a FeatureMap changed its key
+ // TODO Could feature map have duplicate entries and require the same "!isUnique" treatment?
if (isFeatureMapEntryKeyChange(equality, (FeatureMap.Entry)diffCandidate, originValues)) {
featureChange(match, feature, diffCandidate, DifferenceKind.CHANGE,
DifferenceSource.LEFT);
@@ -809,6 +815,23 @@ public class DefaultDiffEngine implements IDiffEngine {
}
}
+ // A Value that is not in the left but present in the origin has been deleted
+ List<Object> leftWithNoLCS = trimLCS(leftValues, lcsOriginLeft, equality);
+ for (Object diffCandidate : originWithNoLCS) {
+ int indexLeft = indexOf(comparison, leftWithNoLCS, diffCandidate);
+ if (indexLeft == -1) {
+ if ((feature instanceof EReference || match.getLeft() != null)
+ && !isFeatureMapChangeOrMove(comparison, feature, diffCandidate, leftValues,
+ DifferenceSource.LEFT)) {
+ featureChange(match, feature, diffCandidate, DifferenceKind.DELETE,
+ DifferenceSource.LEFT);
+ }
+ } else if (!feature.isUnique()) {
+ leftWithNoLCS.remove(indexLeft);
+ }
+ }
+
+ originWithNoLCS = trimLCS(originValues, lcsOriginRight, equality);
lcsCursor = 0;
lcsCurrent = getIfPresent(lcsOriginRight, lcsCursor);
for (Object diffCandidate : rightValues) {
@@ -819,12 +842,14 @@ public class DefaultDiffEngine implements IDiffEngine {
continue;
}
- if (contains(comparison, originValues, diffCandidate)) {
+ int index = indexOf(comparison, originWithNoLCS, diffCandidate);
+ if (index >= 0) {
+ originWithNoLCS.remove(index);
if (checkOrdering) {
featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.RIGHT);
}
} else if (FeatureMapUtil.isFeatureMap(feature) && diffCandidate instanceof FeatureMap.Entry) {
- // A value of a FeatureMap changed his key
+ // A value of a FeatureMap changed its key
if (isFeatureMapEntryKeyChange(equality, (FeatureMap.Entry)diffCandidate, originValues)) {
featureChange(match, feature, diffCandidate, DifferenceKind.CHANGE,
DifferenceSource.RIGHT);
@@ -839,25 +864,19 @@ public class DefaultDiffEngine implements IDiffEngine {
}
}
- // Removed from either side
- for (Object diffCandidate : originValues) {
- // A value that is in the origin but not in one of the side has been deleted.
- // However, we do not want attribute changes on removed elements.
- if (!contains(comparison, leftValues, diffCandidate)) {
- if ((feature instanceof EReference || match.getLeft() != null)
- && !isFeatureMapChangeOrMove(comparison, feature, diffCandidate, leftValues,
- DifferenceSource.LEFT)) {
- featureChange(match, feature, diffCandidate, DifferenceKind.DELETE,
- DifferenceSource.LEFT);
- }
- }
- if (!contains(comparison, rightValues, diffCandidate)) {
+ // A Value that is not in the right but present in the origin has been deleted
+ List<Object> rightWithNoLCS = trimLCS(rightValues, lcsOriginRight, equality);
+ for (Object diffCandidate : originWithNoLCS) {
+ int indexRight = indexOf(comparison, rightWithNoLCS, diffCandidate);
+ if (indexRight == -1) {
if ((feature instanceof EReference || match.getRight() != null)
&& !isFeatureMapChangeOrMove(comparison, feature, diffCandidate, rightValues,
DifferenceSource.RIGHT)) {
featureChange(match, feature, diffCandidate, DifferenceKind.DELETE,
DifferenceSource.RIGHT);
}
+ } else if (!feature.isUnique()) {
+ rightWithNoLCS.remove(indexRight);
}
}
}
@@ -976,6 +995,7 @@ public class DefaultDiffEngine implements IDiffEngine {
final List<Object> lcs = DiffUtil.longestCommonSubsequence(comparison, rightValues, leftValues);
+ List<Object> rightWithNoLCS = trimLCS(rightValues, lcs, equality);
int lcsCursor = 0;
Optional<Object> lcsCurrent = getIfPresent(lcs, lcsCursor);
for (Object diffCandidate : leftValues) {
@@ -986,7 +1006,9 @@ public class DefaultDiffEngine implements IDiffEngine {
continue;
}
- if (contains(comparison, rightValues, diffCandidate)) {
+ int index = indexOf(comparison, rightWithNoLCS, diffCandidate);
+ if (index >= 0) {
+ rightWithNoLCS.remove(index);
if (checkOrdering) {
featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.LEFT);
}
@@ -1006,23 +1028,44 @@ public class DefaultDiffEngine implements IDiffEngine {
}
}
- for (Object diffCandidate : rightValues) {
-
- if (contains(comparison, leftValues, diffCandidate)) {
- // skip elements which were already looked at earlier
- continue;
+ List<Object> leftWithNoLCS = trimLCS(leftValues, lcs, equality);
+ for (Object diffCandidate : rightWithNoLCS) {
+ int index = indexOf(comparison, leftWithNoLCS, diffCandidate);
+ if (index == -1) {
+ // A value that is in the right but not in the left has been deleted or moved.
+ if (isFeatureMapMoveFromNonFeatureMapContainment(comparison, feature, diffCandidate,
+ leftValues, DifferenceSource.LEFT)) {
+ // add move change if the move originates from a non-feature-map containment.
+ featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.LEFT);
+ } else if (!isFeatureMapChangeOrMove(comparison, feature, diffCandidate, leftValues,
+ DifferenceSource.LEFT)) {
+ featureChange(match, feature, diffCandidate, DifferenceKind.DELETE,
+ DifferenceSource.LEFT);
+ }
+ } else if (!feature.isUnique()) {
+ leftWithNoLCS.remove(index);
}
+ }
+ }
- // A value that is in the right but not in the left has been deleted or moved.
- if (isFeatureMapMoveFromNonFeatureMapContainment(comparison, feature, diffCandidate, leftValues,
- DifferenceSource.LEFT)) {
- // add move change if the move originates from a non-feature-map containment.
- featureChange(match, feature, diffCandidate, DifferenceKind.MOVE, DifferenceSource.LEFT);
- } else if (!isFeatureMapChangeOrMove(comparison, feature, diffCandidate, leftValues,
- DifferenceSource.LEFT)) {
- featureChange(match, feature, diffCandidate, DifferenceKind.DELETE, DifferenceSource.LEFT);
+ private List<Object> trimLCS(List<Object> source, List<Object> lcs, IEqualityHelper equalityHelper) {
+ List<Object> result = new ArrayList<>();
+ Iterator<Object> sourceIterator = source.iterator();
+ int lcsCursor = 0;
+ Optional<Object> lcsCurrent = getIfPresent(lcs, lcsCursor);
+ while (sourceIterator.hasNext() && lcsCurrent.isPresent()) {
+ Object current = sourceIterator.next();
+ if (equalityHelper.matchingValues(current, lcsCurrent.get())) {
+ lcsCursor++;
+ lcsCurrent = getIfPresent(lcs, lcsCursor);
+ } else {
+ result.add(current);
}
}
+ while (sourceIterator.hasNext()) {
+ result.add(sourceIterator.next());
+ }
+ return result;
}
/**
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 ba39f3142..4695c340b 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
@@ -28,6 +28,7 @@ import com.google.common.collect.Iterables;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.Monitor;
import org.eclipse.emf.compare.AttributeChange;
+import org.eclipse.emf.compare.ConflictKind;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.DifferenceKind;
import org.eclipse.emf.ecore.EAttribute;
@@ -64,12 +65,14 @@ public class AttributeChangeConflictSearch {
@Override
public void detectConflicts() {
EAttribute feature = diff.getAttribute();
- // Only unique features can conflict
+ // Only unique features can have real conflicts
+ Object value = diff.getValue();
+ EList<Diff> diffsInSameMatch = diff.getMatch().getDifferences();
+ Iterable<Diff> conflictCandidates = Iterables.filter(diffsInSameMatch,
+ and(possiblyConflictingWith(diff), instanceOf(AttributeChange.class), onFeature(feature),
+ ofKind(ADD)));
if (feature.isUnique()) {
- Object value = diff.getValue();
- EList<Diff> diffsInSameMatch = diff.getMatch().getDifferences();
- for (Diff candidate : Iterables.filter(diffsInSameMatch, and(possiblyConflictingWith(diff),
- instanceOf(AttributeChange.class), onFeature(feature), ofKind(ADD)))) {
+ for (Diff candidate : conflictCandidates) {
Object candidateValue = ((AttributeChange)candidate).getValue();
if (comparison.getEqualityHelper().matchingValues(value, candidateValue)) {
// This is a conflict. Is it real?
@@ -80,7 +83,48 @@ public class AttributeChangeConflictSearch {
}
}
}
+ } else {
+ /*
+ * multiple same values can coexist on non-unique features, so we won't detect real conflicts
+ * in such cases. However, if a value is not present in the origin but added in both left and
+ * right, we'll consider it a pseudo conflict to avoid "noise" for the user. If the same value
+ * has been added multiple times on the side(s), we'll only detect pseudo conflict on pairs of
+ * additions and none if there is no longer a pair (i.e. the same value has been added one
+ * more times on one side than in the other).
+ */
+ for (Diff candidate : conflictCandidates) {
+ Object candidateValue = ((AttributeChange)candidate).getValue();
+ if (comparison.getEqualityHelper().matchingValues(value, candidateValue)) {
+ // potential pseudo-conflict
+ // is this candidate already paired in a conflict?
+ if (candidate.getConflict() != null
+ && candidate.getConflict().getKind() == ConflictKind.PSEUDO) {
+ if (candidate.getConflict().getDifferences().stream()
+ .filter(AttributeChange.class::isInstance)
+ .anyMatch(conflictingWith -> matchingConflictingDiff(diff,
+ (AttributeChange)conflictingWith))) {
+ // continue to next candidate
+ continue;
+ }
+ }
+ conflict(candidate, PSEUDO);
+ // break the loop to prevent further matching add conflicts
+ break;
+ }
+ }
+ }
+ }
+
+ private boolean matchingConflictingDiff(AttributeChange reference, AttributeChange candidate) {
+ if (reference == candidate) {
+ return false;
+ }
+ if (reference.getMatch() == candidate.getMatch() && reference.getKind() == candidate.getKind()) {
+ Object referenceValue = reference.getValue();
+ Object candidateValue = candidate.getValue();
+ return comparison.getEqualityHelper().matchingValues(referenceValue, candidateValue);
}
+ return false;
}
}
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 28eeff05c..68dfd84cb 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
@@ -27,6 +27,7 @@ import java.lang.ref.WeakReference;
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;
@@ -298,20 +299,21 @@ public final class DiffUtil {
final List<E> copy1 = Lists.newArrayList(sequence1);
final List<E> copy2 = Lists.newArrayList(sequence2);
- Object[] ignoredElementsArray = Iterables.toArray(ignoredElements, Object.class);
+ List<Object> ignoredElementsList = new ArrayList<>();
+ ignoredElements.forEach(ignoredElementsList::add);
// Reduce sets
- final List<E> prefix = trimPrefix(comparison, equalityHelper, ignoredElementsArray, copy1, copy2);
- final List<E> suffix = trimSuffix(comparison, equalityHelper, ignoredElementsArray, copy1, copy2);
+ final List<E> prefix = trimPrefix(comparison, equalityHelper, ignoredElementsList, copy1, copy2);
+ final List<E> suffix = trimSuffix(comparison, equalityHelper, ignoredElementsList, copy1, copy2);
final List<E> subLCS;
// FIXME extract an interface for the LCS and properly separate these two differently typed
// implementations.
if (copy1.size() > Short.MAX_VALUE || copy2.size() > Short.MAX_VALUE) {
- subLCS = intLongestCommonSubsequence(comparison, equalityHelper, ignoredElementsArray, copy1,
+ subLCS = intLongestCommonSubsequence(comparison, equalityHelper, ignoredElementsList, copy1,
copy2);
} else {
- subLCS = shortLongestCommonSubsequence(comparison, equalityHelper, ignoredElementsArray, copy1,
+ subLCS = shortLongestCommonSubsequence(comparison, equalityHelper, ignoredElementsList, copy1,
copy2);
}
@@ -389,10 +391,13 @@ public final class DiffUtil {
* returns.
*/
private static <E> List<E> trimPrefix(Comparison comparison, IEqualityHelper equalityHelper,
- Object[] ignoredElements, List<E> sequence1, List<E> sequence2) {
+ List<Object> ignoredElements, List<E> sequence1, List<E> sequence2) {
final int size1 = sequence1.size();
final int size2 = sequence2.size();
+ List<Object> ignoredElements1 = new ArrayList<>(ignoredElements);
+ List<Object> ignoredElements2 = new ArrayList<>(ignoredElements);
+
final List<E> prefix = Lists.newArrayList();
int start1 = 1;
int start2 = 1;
@@ -405,15 +410,17 @@ public final class DiffUtil {
start1++;
start2++;
} else {
- boolean ignore1 = contains(equalityHelper, ignoredElements, first);
- boolean ignore2 = contains(equalityHelper, ignoredElements, second);
- if (ignore1) {
+ int ignore1 = indexOf(equalityHelper, ignoredElements1, first);
+ if (ignore1 != -1) {
+ ignoredElements1.remove(ignore1);
start1++;
}
- if (ignore2) {
+ int ignore2 = indexOf(equalityHelper, ignoredElements2, second);
+ if (ignore2 != -1) {
+ ignoredElements2.remove(ignore2);
start2++;
}
- if (!ignore1 && !ignore2) {
+ if (ignore1 == -1 && ignore2 == -1) {
matching = false;
}
}
@@ -448,10 +455,13 @@ public final class DiffUtil {
* returns.
*/
private static <E> List<E> trimSuffix(Comparison comparison, IEqualityHelper equalityHelper,
- Object[] ignoredElements, List<E> sequence1, List<E> sequence2) {
+ List<Object> ignoredElements, List<E> sequence1, List<E> sequence2) {
final int size1 = sequence1.size();
final int size2 = sequence2.size();
+ List<Object> ignoredElements1 = new ArrayList<>(ignoredElements);
+ List<Object> ignoredElements2 = new ArrayList<>(ignoredElements);
+
final List<E> suffix = Lists.newArrayList();
int end1 = size1;
int end2 = size2;
@@ -464,15 +474,17 @@ public final class DiffUtil {
end1--;
end2--;
} else {
- boolean ignore1 = contains(equalityHelper, ignoredElements, first);
- boolean ignore2 = contains(equalityHelper, ignoredElements, second);
- if (ignore1) {
+ int ignore1 = indexOf(equalityHelper, ignoredElements1, first);
+ if (ignore1 != -1) {
+ ignoredElements1.remove(ignore1);
end1--;
}
- if (ignore2) {
+ int ignore2 = indexOf(equalityHelper, ignoredElements2, second);
+ if (ignore2 != -1) {
+ ignoredElements2.remove(ignore2);
end2--;
}
- if (!ignore1 && !ignore2) {
+ if (ignore1 == -1 && ignore2 == -1) {
matching = false;
}
}
@@ -493,17 +505,16 @@ public final class DiffUtil {
* The sequence which elements we need to compare with {@code element}.
* @param element
* The element we are seeking in {@code sequence}.
- * @return {@code true} if the given {@code sequence} contains an element matching {@code element},
- * {@code false} otherwise.
+ * @return index of the given {@code element} in {@code sequence} if any, {@code -1} otherwise.
* @see IEqualityHelper#matchingValues(Comparison, Object, Object)
*/
- private static boolean contains(IEqualityHelper equalityHelper, Object[] sequence, Object element) {
- for (Object candidate : sequence) {
- if (equalityHelper.matchingValues(element, candidate)) {
- return true;
+ private static int indexOf(IEqualityHelper equalityHelper, List<Object> sequence, Object element) {
+ for (int i = 0; i < sequence.size(); i++) {
+ if (equalityHelper.matchingValues(element, sequence.get(i))) {
+ return i;
}
}
- return false;
+ return -1;
}
/**
@@ -526,7 +537,8 @@ public final class DiffUtil {
* sequences.
*/
private static <E> List<E> shortLongestCommonSubsequence(Comparison comparison,
- IEqualityHelper equalityHelper, Object[] ignoredElements, List<E> sequence1, List<E> sequence2) {
+ IEqualityHelper equalityHelper, List<Object> ignoredElements, List<E> sequence1,
+ List<E> sequence2) {
final int size1 = sequence1.size();
final int size2 = sequence2.size();
@@ -545,7 +557,7 @@ public final class DiffUtil {
} else {
final E second = sequence2.get(j - 1);
if (equalityHelper.matchingValues(first, second)
- && !contains(equalityHelper, ignoredElements, second)) {
+ && indexOf(equalityHelper, ignoredElements, second) == -1) {
matrix[i][j] = (short)(1 + current);
} else {
matrix[i][j] = nextIfNoMatch;
@@ -597,7 +609,8 @@ public final class DiffUtil {
* sequences.
*/
private static <E> List<E> intLongestCommonSubsequence(Comparison comparison,
- IEqualityHelper equalityHelper, Object[] ignoredElements, List<E> sequence1, List<E> sequence2) {
+ IEqualityHelper equalityHelper, List<Object> ignoredElements, List<E> sequence1,
+ List<E> sequence2) {
final int size1 = sequence1.size();
final int size2 = sequence2.size();
@@ -616,7 +629,7 @@ public final class DiffUtil {
} else {
final E second = sequence2.get(j - 1);
if (equalityHelper.matchingValues(first, second)
- && !contains(equalityHelper, ignoredElements, second)) {
+ && indexOf(equalityHelper, ignoredElements, second) == -1) {
matrix[i][j] = 1 + current;
} else {
matrix[i][j] = nextIfNoMatch;
@@ -718,13 +731,28 @@ public final class DiffUtil {
}
ListIterator<E> sourceIterator = source.listIterator();
+ Iterator<E> lcsIterator = lcs.iterator();
+ E currentLCS = null;
+ if (lcsIterator.hasNext()) {
+ currentLCS = lcsIterator.next();
+ }
for (int i = 0; sourceIterator.hasNext() && (currentIndex == -1 || firstLCSIndex == -1); i++) {
final E sourceElement = sourceIterator.next();
- if (currentIndex == -1 && equalityHelper.matchingValues(sourceElement, newElement)) {
- currentIndex = i;
+ if (currentLCS != null && equalityHelper.matchingValues(sourceElement, currentLCS)) {
+ if (firstLCSIndex == -1) {
+ firstLCSIndex = i;
+ }
+ if (lcsIterator.hasNext()) {
+ currentLCS = lcsIterator.next();
+ } else {
+ currentLCS = null;
+ }
+ // If this is a part of the LCS, it cannot be the current element (might be duplicates, so we
+ // have to <continue> here)
+ continue;
}
- if (firstLCSIndex == -1 && equalityHelper.matchingValues(sourceElement, firstLCS)) {
- firstLCSIndex = i;
+ if (equalityHelper.matchingValues(sourceElement, newElement)) {
+ currentIndex = i;
}
}
// The list may contain duplicates, use a reverse iteration to find the last from LCS.
@@ -761,8 +789,93 @@ public final class DiffUtil {
}
/**
+ * This will try and determine the index at which a given element from the {@code source} list should be
+ * inserted in the {@code target} list.
+ * <p>
+ * The expected insertion index will always be relative to the Longest Common Subsequence (LCS) between
+ * the two given lists.
+ * </p>
+ *
+ * @param comparison
+ * This will be used in order to retrieve the Match for EObjects when comparing them.
+ * @param source
+ * The List from which one element has to be added to the {@code target} list.
+ * @param target
+ * The List into which one element from {@code source} has to be added.
+ * @param lcs
+ * The precomputed LCS between these two lists.
+ * @param currentIndexInSource
+ * The current index (in source) of the element we want to insert in target.
+ * @param <E>
+ * Type of the sequences content.
+ * @return The index at which {@code newElement} should be inserted in {@code target}.
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public static <E> int findInsertionIndexForElementAt(Comparison comparison, List<E> source,
+ List<E> target, List<E> lcs, int currentIndexInSource) {
+ final IEqualityHelper equalityHelper = comparison.getEqualityHelper();
+
+ E firstLCS = null;
+ E lastLCS = null;
+ int lcsSize = lcs.size();
+ if (lcsSize > 0) {
+ firstLCS = lcs.get(0);
+ lastLCS = lcs.get(lcsSize - 1);
+ }
+
+ final int noLCS = -2;
+ int firstLCSIndex = -1;
+ int lastLCSIndex = -1;
+ if (firstLCS == null) {
+ // We have no LCS
+ firstLCSIndex = noLCS;
+ lastLCSIndex = noLCS;
+ }
+
+ ListIterator<E> sourceIterator = source.listIterator();
+ for (int i = 0; sourceIterator.hasNext() && firstLCSIndex == -1; i++) {
+ final E sourceElement = sourceIterator.next();
+ if (firstLCSIndex == -1 && equalityHelper.matchingValues(sourceElement, firstLCS)) {
+ firstLCSIndex = i;
+ }
+ }
+ // The list may contain duplicates, use a reverse iteration to find the last from LCS.
+ final int sourceSize = source.size();
+ sourceIterator = source.listIterator(sourceSize);
+ for (int i = sourceSize - 1; sourceIterator.hasPrevious() && lastLCSIndex == -1; i--) {
+ final E sourceElement = sourceIterator.previous();
+ if (lastLCSIndex == -1 && equalityHelper.matchingValues(lastLCS, sourceElement)) {
+ lastLCSIndex = i;
+ }
+ }
+
+ int insertionIndex = -1;
+ if (firstLCSIndex == noLCS) {
+ // We have no LCS. The two lists have no element in common. Insert at the very end of the target.
+ insertionIndex = target.size();
+ } else if (currentIndexInSource < firstLCSIndex) {
+ // The object we are to insert is before the LCS in source.
+ insertionIndex = insertBeforeLCS(target, equalityHelper, firstLCS);
+ } else if (currentIndexInSource > lastLCSIndex) {
+ // The object we are to insert is after the LCS in source.
+ insertionIndex = findInsertionIndexAfterLCS(target, equalityHelper, lastLCS);
+ } else {
+ // Our object is in-between two elements A and B of the LCS in source
+ insertionIndex = findInsertionIndexWithinLCS(source, target, equalityHelper, lcs,
+ currentIndexInSource);
+ }
+
+ // We somehow failed to determine the insertion index. Insert at the very end.
+ if (insertionIndex == -1) {
+ insertionIndex = target.size();
+ }
+
+ return insertionIndex;
+ }
+
+ /**
* This will be called to try and find the insertion index for an element that is located in-between two
- * elements of the LCS between {@code source} and {@code target}.
+ * elements A and B of the LCS between {@code source} and {@code target}.
*
* @param source
* The List from which one element has to be added to the {@code target} list.
@@ -1240,7 +1353,7 @@ public final class DiffUtil {
* @return The list of elements that should be ignored when computing the insertion index for a new
* element in {@code candidates}.
*/
- private static <E> Set<E> computeIgnoredElements(Comparison comparison, IEqualityHelper equalityHelper,
+ public static <E> Set<E> computeIgnoredElements(Comparison comparison, IEqualityHelper equalityHelper,
List<E> candidates, final Diff diff, boolean rightToLeft) {
// There is no point doing any computations if the candidates list is empty.
if (!candidates.isEmpty()) {
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java
index 6b915f6e7..200e362d9 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java
@@ -15,7 +15,11 @@ import static org.eclipse.emf.compare.utils.ReferenceUtil.safeEGet;
import static org.eclipse.emf.compare.utils.ReferenceUtil.safeEIsSet;
import static org.eclipse.emf.compare.utils.ReferenceUtil.safeESet;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.compare.AttributeChange;
@@ -25,6 +29,7 @@ import org.eclipse.emf.compare.DifferenceSource;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.internal.ThreeWayTextDiff;
import org.eclipse.emf.compare.internal.utils.DiffUtil;
+import org.eclipse.emf.compare.utils.IEqualityHelper;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
@@ -190,18 +195,75 @@ public class AttributeChangeMerger extends AbstractMerger {
final EStructuralFeature attribute = diff.getAttribute();
// We have the container, attribute and value to remove.
if (attribute.isMany()) {
- /*
- * TODO if the same value appears twice, should we try and find the one that has actually been
- * deleted? Will it happen that often? For now, remove the first occurence we find.
- */
- final List<Object> targetList = (List<Object>)safeEGet(currentContainer, attribute);
- targetList.remove(expectedValue);
+ if (attribute.isUnique()) {
+ final List<Object> targetList = (List<Object>)safeEGet(currentContainer, attribute);
+ targetList.remove(expectedValue);
+ } else {
+ removeNonUniqueFromTarget(diff, rightToLeft);
+ }
} else {
currentContainer.eUnset(attribute);
}
}
}
+ @SuppressWarnings("unchecked")
+ private void removeNonUniqueFromTarget(AttributeChange diff, boolean rightToLeft) {
+ Comparison comparison = diff.getMatch().getComparison();
+ IEqualityHelper equalityHelper = comparison.getEqualityHelper();
+ EAttribute attribute = diff.getAttribute();
+
+ EObject sourceContainer;
+ EObject targetContainer;
+ if (rightToLeft) {
+ sourceContainer = diff.getMatch().getRight();
+ targetContainer = diff.getMatch().getLeft();
+ } else {
+ sourceContainer = diff.getMatch().getLeft();
+ targetContainer = diff.getMatch().getRight();
+ }
+
+ List<Object> sourceList = (List<Object>)safeEGet(sourceContainer, attribute);
+ List<Object> targetList = (List<Object>)safeEGet(targetContainer, attribute);
+ Object valueToRemove = diff.getValue();
+
+ List<Object> lcs = DiffUtil.longestCommonSubsequence(comparison, sourceList, targetList);
+
+ // The current index, in the target list, of that value
+ int currentIndexInTarget = -1;
+ Iterator<Object> lcsIteratorForTargetLookup = lcs.iterator();
+ Object currentLCS = null;
+ if (lcsIteratorForTargetLookup.hasNext()) {
+ currentLCS = lcsIteratorForTargetLookup.next();
+ }
+ for (int j = 0; j < targetList.size() && currentIndexInTarget == -1; j++) {
+ if (currentLCS == null) {
+ // we've iterated on our whole LCS.
+ // first instance of our target is the one to move.
+ if (equalityHelper.matchingAttributeValues(targetList.get(j), valueToRemove)) {
+ currentIndexInTarget = j;
+ }
+ } else if (equalityHelper.matchingAttributeValues(targetList.get(j), currentLCS)) {
+ // this matches our current lcs item. continue to next one if any
+ if (lcsIteratorForTargetLookup.hasNext()) {
+ currentLCS = lcsIteratorForTargetLookup.next();
+ } else {
+ currentLCS = null;
+ }
+ } else {
+ // This item is not in our LCS. Is it the one we're looking for?
+ if (equalityHelper.matchingAttributeValues(targetList.get(j), valueToRemove)) {
+ currentIndexInTarget = j;
+ }
+ }
+ }
+ // value might not exist in target list if it has already been removed or if this was a pseudo
+ // conflict deletion
+ if (currentIndexInTarget >= 0) {
+ targetList.remove(currentIndexInTarget);
+ }
+ }
+
/**
* This will be called when trying to copy a "MOVE" diff.
*
@@ -239,40 +301,159 @@ public class AttributeChangeMerger extends AbstractMerger {
* @param rightToLeft
* Whether we should move the value in the left or right side.
*/
- @SuppressWarnings("unchecked")
protected void doMove(AttributeChange diff, Comparison comparison, EObject expectedContainer,
Object expectedValue, boolean rightToLeft) {
final EStructuralFeature attribute = diff.getAttribute();
if (attribute.isMany()) {
- // Element to move cannot be part of the LCS... or there would not be a MOVE diff
- int insertionIndex = findInsertionIndex(comparison, diff, rightToLeft);
- /*
- * However, it could still have been located "before" its new index, in which case we need to take
- * it into account.
- */
- final List<Object> targetList = (List<Object>)safeEGet(expectedContainer, attribute);
- final int currentIndex = targetList.indexOf(expectedValue);
- if (insertionIndex > currentIndex) {
- insertionIndex--;
+ if (!attribute.isUnique()) {
+ doMoveNonUniqueAttribute(diff, comparison, rightToLeft);
+ } else {
+ doMoveUniqueAttribute(diff, comparison, expectedContainer, expectedValue, rightToLeft);
}
+ } else {
+ // This will never happen with the default diff engine, but may still be done from extenders
+ safeESet(expectedContainer, attribute, expectedValue);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void doMoveUniqueAttribute(AttributeChange diff, Comparison comparison, EObject expectedContainer,
+ Object expectedValue, boolean rightToLeft) {
+ final EStructuralFeature attribute = diff.getAttribute();
+
+ // Element to move cannot be part of the LCS... or there would not be a MOVE diff
+ int insertionIndex = findInsertionIndex(comparison, diff, rightToLeft);
+ /*
+ * However, it could still have been located "before" its new index, in which case we need to take it
+ * into account.
+ */
+ final List<Object> targetList = (List<Object>)safeEGet(expectedContainer, attribute);
+ final int currentIndex = targetList.indexOf(expectedValue);
+ if (insertionIndex > currentIndex) {
+ insertionIndex--;
+ }
- if (targetList instanceof EList<?>) {
- if (insertionIndex < 0 || insertionIndex >= targetList.size()) {
- ((EList<Object>)targetList).move(targetList.size() - 1, expectedValue);
+ if (targetList instanceof EList<?>) {
+ if (insertionIndex < 0 || insertionIndex >= targetList.size()) {
+ ((EList<Object>)targetList).move(targetList.size() - 1, expectedValue);
+ } else {
+ ((EList<Object>)targetList).move(insertionIndex, expectedValue);
+ }
+ } else {
+ targetList.remove(expectedValue);
+ if (insertionIndex < 0 || insertionIndex > targetList.size()) {
+ targetList.add(expectedValue);
+ } else {
+ targetList.add(insertionIndex, expectedValue);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void doMoveNonUniqueAttribute(AttributeChange diff, Comparison comparison, boolean rightToLeft) {
+ IEqualityHelper equalityHelper = comparison.getEqualityHelper();
+ EAttribute attribute = diff.getAttribute();
+
+ EObject sourceContainer;
+ EObject targetContainer;
+ if (rightToLeft) {
+ sourceContainer = diff.getMatch().getRight();
+ targetContainer = diff.getMatch().getLeft();
+ } else {
+ sourceContainer = diff.getMatch().getLeft();
+ targetContainer = diff.getMatch().getRight();
+ }
+
+ List<Object> sourceList = (List<Object>)safeEGet(sourceContainer, attribute);
+ List<Object> targetList = (List<Object>)safeEGet(targetContainer, attribute);
+ // copy this one : we'll have to modify target while iterating over this view
+ List<Object> copyTarget = new ArrayList<>(targetList);
+ Object valueToMove = diff.getValue();
+
+ Set<Object> ignoredElements = DiffUtil.computeIgnoredElements(comparison, equalityHelper, targetList,
+ diff, rightToLeft);
+ if (ignoredElements.isEmpty()) {
+ ignoredElements = Collections.singleton(valueToMove);
+ } else {
+ ignoredElements.add(valueToMove);
+ }
+ List<Object> lcs = DiffUtil.longestCommonSubsequence(comparison, ignoredElements, sourceList,
+ copyTarget);
+
+ // We need to find the current index, in the source list, of the value to move
+ int currentIndexInSource = -1;
+ Iterator<Object> lcsIteratorForSourceLookup = lcs.iterator();
+ Object currentLCS = null;
+ if (lcsIteratorForSourceLookup.hasNext()) {
+ currentLCS = lcsIteratorForSourceLookup.next();
+ }
+ for (int j = 0; j < sourceList.size() && currentIndexInSource == -1; j++) {
+ if (currentLCS == null) {
+ // we've iterated on our whole LCS.
+ // first instance of our target is the one to move.
+ if (equalityHelper.matchingAttributeValues(sourceList.get(j), valueToMove)) {
+ currentIndexInSource = j;
+ }
+ } else if (equalityHelper.matchingAttributeValues(sourceList.get(j), currentLCS)) {
+ // this matches our current lcs item. continue to next one if any
+ if (lcsIteratorForSourceLookup.hasNext()) {
+ currentLCS = lcsIteratorForSourceLookup.next();
} else {
- ((EList<Object>)targetList).move(insertionIndex, expectedValue);
+ currentLCS = null;
}
} else {
- targetList.remove(expectedValue);
- if (insertionIndex < 0 || insertionIndex > targetList.size()) {
- targetList.add(expectedValue);
+ // This item is not in our LCS. Is it the one we're looking for?
+ if (equalityHelper.matchingAttributeValues(sourceList.get(j), valueToMove)) {
+ currentIndexInSource = j;
+ }
+ }
+ }
+ // The current index, in the target list, of that value
+ int currentIndexInTarget = -1;
+ Iterator<Object> lcsIteratorForTargetLookup = lcs.iterator();
+ currentLCS = null;
+ if (lcsIteratorForTargetLookup.hasNext()) {
+ currentLCS = lcsIteratorForTargetLookup.next();
+ }
+ for (int j = 0; j < targetList.size() && currentIndexInTarget == -1; j++) {
+ if (currentLCS == null) {
+ // we've iterated on our whole LCS.
+ // first instance of our target is the one to move.
+ if (equalityHelper.matchingAttributeValues(targetList.get(j), valueToMove)) {
+ currentIndexInTarget = j;
+ }
+ } else if (equalityHelper.matchingAttributeValues(targetList.get(j), currentLCS)) {
+ // this matches our current lcs item. continue to next one if any
+ if (lcsIteratorForTargetLookup.hasNext()) {
+ currentLCS = lcsIteratorForTargetLookup.next();
} else {
- targetList.add(insertionIndex, expectedValue);
+ currentLCS = null;
+ }
+ } else {
+ // This item is not in our LCS. Is it the one we're looking for?
+ if (equalityHelper.matchingAttributeValues(targetList.get(j), valueToMove)) {
+ currentIndexInTarget = j;
}
}
+ }
+
+ // Then the index, in the target, at which this value needs to be moved
+ int insertionIndex = DiffUtil.findInsertionIndexForElementAt(comparison, sourceList, copyTarget, lcs,
+ currentIndexInSource);
+
+ if (targetList instanceof EList<?>) {
+ if (insertionIndex < 0 || insertionIndex >= targetList.size()) {
+ ((EList<Object>)targetList).move(targetList.size() - 1, currentIndexInTarget);
+ } else {
+ ((EList<Object>)targetList).move(insertionIndex, currentIndexInTarget);
+ }
} else {
- // This will never happen with the default diff engine, but may still be done from extenders
- safeESet(expectedContainer, attribute, expectedValue);
+ targetList.remove(currentIndexInTarget);
+ if (insertionIndex < 0 || insertionIndex > targetList.size()) {
+ targetList.add(valueToMove);
+ } else {
+ targetList.add(insertionIndex, valueToMove);
+ }
}
}

Back to the top