| /******************************************************************************* |
| * Copyright (c) 2014, 2016 Obeo and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Obeo - initial API and implementation |
| * Philip Langer - bug 501864 |
| *******************************************************************************/ |
| package org.eclipse.emf.compare.uml2.tests.stereotypes; |
| |
| import static com.google.common.base.Predicates.and; |
| import static com.google.common.base.Predicates.instanceOf; |
| import static org.eclipse.emf.compare.merge.AbstractMerger.isInTerminalState; |
| import static org.eclipse.emf.compare.utils.EMFComparePredicates.added; |
| import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind; |
| import static org.eclipse.emf.compare.utils.EMFComparePredicates.removed; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertSame; |
| import static org.junit.Assert.assertTrue; |
| |
| import com.google.common.base.Function; |
| import com.google.common.base.Predicate; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.ImmutableSet.Builder; |
| import com.google.common.collect.Iterables; |
| |
| import java.io.IOException; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.emf.common.util.BasicMonitor; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.compare.AttributeChange; |
| import org.eclipse.emf.compare.Comparison; |
| import org.eclipse.emf.compare.Conflict; |
| import org.eclipse.emf.compare.Diff; |
| import org.eclipse.emf.compare.DifferenceKind; |
| import org.eclipse.emf.compare.DifferenceState; |
| import org.eclipse.emf.compare.ReferenceChange; |
| import org.eclipse.emf.compare.merge.BatchMerger; |
| import org.eclipse.emf.compare.tests.postprocess.data.TestPostProcessor; |
| import org.eclipse.emf.compare.uml2.internal.StereotypedElementChange; |
| import org.eclipse.emf.compare.uml2.internal.postprocessor.StereotypedElementChangePostProcessor; |
| import org.eclipse.emf.compare.uml2.tests.AbstractUMLProfileTest; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.uml2.uml.Class; |
| import org.eclipse.uml2.uml.Model; |
| import org.eclipse.uml2.uml.util.UMLUtil; |
| |
| /** |
| * Abstract class used to test the merge of {@link StereotypedElementChange}. |
| * |
| * @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a> |
| */ |
| public abstract class AbstractStereotypedElementChangeTests extends AbstractUMLProfileTest { |
| |
| /** |
| * Each sublass of AbstractUMLTest have to call this method in a @BeforeClass annotated method. This allow |
| * each test to customize its context. |
| */ |
| public static void beforeClass() { |
| addProfilePathmap(); |
| } |
| |
| /** |
| * Each sublass of AbstractUMLTest have to call this method in a @BeforeClass annotated method. This allow |
| * each test to safely delete its context. |
| */ |
| public static void afterClass() { |
| resetProfilePathmap(); |
| } |
| |
| @Override |
| protected void registerPostProcessors( |
| org.eclipse.emf.compare.postprocessor.IPostProcessor.Descriptor.Registry<String> postProcessorRegistry) { |
| super.registerPostProcessors(postProcessorRegistry); |
| postProcessorRegistry.put(StereotypedElementChangePostProcessor.class.getName(), |
| new TestPostProcessor.TestPostProcessorDescriptor( |
| Pattern.compile("http://www.eclipse.org/uml2/\\d\\.0\\.0/UML"), null, //$NON-NLS-1$ |
| new StereotypedElementChangePostProcessor(), 25)); |
| } |
| |
| /** |
| * Tests that no {@link StereotypedElementChange} is created when applying a stereotype on an existing |
| * element. |
| * <p> |
| * <h3>Inputs</h4> |
| * </p> |
| * <h3>Left model</h3> |
| * |
| * <pre> |
| * <Model> aModel |
| * `-- <<ACliche>> <Class> Test |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche>> <Class> Test]</b> |
| * </pre> |
| * |
| * <h3>Right model</h3> |
| * |
| * <pre> |
| * <Model> aModel |
| * `-- <Class> Test |
| * </pre> |
| * |
| * @throws IOException |
| */ |
| protected void testApplyStereotypeOnExistingElement(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| EList<Diff> differences = comparison.getDifferences(); |
| Iterable<StereotypedElementChange> stereotypesChanges = getStereotypedElementChanges(differences, |
| DifferenceKind.ADD); |
| assertEquals(0, Iterables.size(stereotypesChanges)); |
| |
| } |
| |
| /** |
| * Tests that no {@link StereotypedElementChange} is created when unapplying a stereotype. |
| * <p> |
| * <h3>Inputs</h4> |
| * </p> |
| * <h3>Left model</h3> |
| * |
| * <pre> |
| * <Model> aModel |
| * `-- <Class> Test |
| * </pre> |
| * |
| * <h3>Right model</h3> |
| * |
| * <pre> |
| * <Model> aModel |
| * `-- <<ACliche>> <Class> Test |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche>> <Class> Test]</b> |
| * </pre> |
| * |
| * @throws IOException |
| */ |
| protected void testRemoveStereotypeOnExistingElement(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| EList<Diff> differences = comparison.getDifferences(); |
| Iterable<StereotypedElementChange> stereotypesChanges = getStereotypedElementChanges(differences, |
| DifferenceKind.DELETE); |
| assertEquals(0, Iterables.size(stereotypesChanges)); |
| |
| } |
| |
| /** |
| * Tests basic use case: |
| * <ol> |
| * <li>Creates a {@link StereotypedElementChange} of kind {@link DifferenceKind#ADD}</li> |
| * <li>Merges it from left to right</li> |
| * </ol> |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <b><<ACliche>> <Class> Class0</b> |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche>> <Class> Class0]</b> |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * |
| * <h4>Expected right model after merging</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche>> <Class> Class0 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class0] |
| * </pre> |
| * </p> |
| * |
| * @throws IOException |
| */ |
| protected void testAddStereotypedElementMergeLToR(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| // Checks comparison model |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.ADD, 2); |
| |
| assertAddedBaseElementDiff(differences, "model.Class0", stereotypedElementChange); //$NON-NLS-1$ |
| |
| // Merges |
| mergeLeftToRight(stereotypedElementChange); |
| |
| // Checks comparison model state |
| for (Diff diff : differences) { |
| assertSame(DifferenceState.MERGED, diff.getState()); |
| } |
| |
| // Checks right model content after merging |
| assertEqualsM1(right); |
| |
| // Checks left model content after merging |
| assertEqualsM1(left); |
| |
| } |
| |
| /** |
| * Tests basic use case: |
| * <ol> |
| * <li>Creates a {@link StereotypedElementChange} of kind {@link DifferenceKind#DELETE}</li> |
| * <li>Merges it from left to right</li> |
| * </ol> |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `--<b> <<ACliche>> <Class> Class0</b> |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche>> <Class> Class0]</b> |
| * </pre> |
| * |
| * <h4>Expected right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * </p> |
| * |
| * @throws IOException |
| */ |
| protected void testDelStereotypedElementMergeLToR(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| // Checks comparison model |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.DELETE, 2); |
| |
| assertDeletedBaseElementDiff(differences, "model.Class0", stereotypedElementChange); //$NON-NLS-1$ |
| |
| // Merges |
| mergeLeftToRight(stereotypedElementChange); |
| |
| // Checks comparison model |
| for (Diff diff : differences) { |
| assertSame(DifferenceState.MERGED, diff.getState()); |
| } |
| |
| // Checks right model content after merging |
| assertEqualsM2(right); |
| |
| // Checks left model content after merging |
| assertEqualsM2(left); |
| } |
| |
| /** |
| * Tests basic use case: |
| * <ol> |
| * <li>Creates a {@link StereotypedElementChange} of kind {@link DifferenceKind#ADD}</li> |
| * <li>Merges it from right to left</li> |
| * </ol> |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <b><<ACliche>> <Class> Class0</b> |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche>> <Class> Class0]</b> |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * |
| * <h4>Expected left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * </p> |
| * |
| * @throws IOException |
| */ |
| protected void testAddStereotypedElementMergeRToL(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| // Checks comparison model |
| EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.ADD, 2); |
| assertAddedBaseElementDiff(differences, "model.Class0", stereotypedElementChange); //$NON-NLS-1$ |
| |
| // Merges |
| mergeRightToLeft(stereotypedElementChange); |
| |
| // Checks comparison model after merging |
| for (Diff diff : differences) { |
| assertTrue(isInTerminalState(diff)); |
| } |
| |
| // Checks right model content after merging |
| assertEqualsM2(right); |
| |
| // Checks left model content after merging |
| assertEqualsM2(left); |
| } |
| |
| /** |
| * Tests basic use case: |
| * <ol> |
| * <li>Creates a {@link StereotypedElementChange} of kind {@link DifferenceKind#DELETE}</li> |
| * <li>Merges it from right to left</li> |
| * </ol> |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <b><<ACliche>> <Class> Class0</b> |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche>> <Class> Class0]</b> |
| * </pre> |
| * |
| * <h4>Expected left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche>> <Class> Class0 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class0] |
| * </pre> |
| * </p> |
| * |
| * @throws IOException |
| */ |
| protected void testDelStereotypedElementMergeRToL(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| // Checks model structure |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.DELETE, 2); |
| |
| assertDeletedBaseElementDiff(differences, "model.Class0", stereotypedElementChange); //$NON-NLS-1$ |
| |
| // Merges |
| mergeRightToLeft(stereotypedElementChange); |
| for (Diff diff : differences) { |
| assertTrue(isInTerminalState(diff)); |
| } |
| |
| // Checks right model content after merging |
| assertEqualsM1(right); |
| |
| // Checks left model content after merging |
| assertEqualsM1(left); |
| } |
| |
| /** |
| * Tests advanced use case: |
| * <ol> |
| * <li>Creates a {@link StereotypedElementChange} of kind {@link DifferenceKind#ADD} with dependencies |
| * (requires creation of parent + profile application)</li> |
| * <li>Merges it from left to right</li> |
| * </ol> |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <b><Model> MyNiceModel |
| * `-- <<ACliche>> <Class> Class1 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class1]</b> |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * </pre> |
| * |
| * <h4>Expected right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Model> MyNiceModel |
| * `-- <<ACliche>> <Class> Class1 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class1] |
| * </pre> |
| * </p> |
| * |
| * @throws IOException |
| */ |
| protected void testAddStereotypedElementLToR2(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| // Checks model structure |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.ADD, 2); |
| |
| assertAddedBaseElementDiff(differences, "model.MyNiceModel.Class1", stereotypedElementChange); //$NON-NLS-1$ |
| |
| // Merge |
| mergeLeftToRight(stereotypedElementChange); |
| |
| // Checks comparison model |
| for (Diff diff : differences) { |
| assertSame(DifferenceState.MERGED, diff.getState()); |
| } |
| |
| // Checks right model content after merging |
| assertEqualsM3(right); |
| |
| // Checks left model content after merging |
| assertEqualsM3(left); |
| |
| } |
| |
| /** |
| * Tests advanced use case: |
| * <ol> |
| * <li>Creates a {@link StereotypedElementChange} of kind {@link DifferenceKind#DELETE} with dependencies |
| * (requires creation of parent + profile application)</li> |
| * <li>Merges it from left to right</li> |
| * </ol> |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Model> MyNiceModel |
| * `-- <<ACliche>> <Class> Class1 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class1] |
| * </pre> |
| * |
| * <h4>Expected right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Model> MyNiceModel |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * </p> |
| * |
| * @throws IOException |
| */ |
| protected void testDelStereotypedElementLToR2(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| // Checks differences |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.DELETE, 2); |
| |
| assertDeletedBaseElementDiff(differences, "model.MyNiceModel.Class1", stereotypedElementChange); //$NON-NLS-1$ |
| |
| // Merges |
| mergeLeftToRight(stereotypedElementChange); |
| |
| // Checks comparison model |
| Set<Diff> expectedMergeDifferences = getRefinedByClosure(stereotypedElementChange); |
| for (Diff diff : differences) { |
| final DifferenceState expectedDiffState; |
| if (expectedMergeDifferences.contains(diff) || stereotypedElementChange.equals(diff)) { |
| expectedDiffState = DifferenceState.MERGED; |
| } else { |
| expectedDiffState = DifferenceState.UNRESOLVED; |
| } |
| assertSame(expectedDiffState, diff.getState()); |
| } |
| |
| // Checks the content of the right model after merging |
| // @formatter:off |
| EList<EObject> contents = right.getContents(); |
| assertEquals(1, contents.size()); |
| Model model = (Model)contents.get(0); |
| assertEquals(1, model.getPackagedElements().size()); |
| Model subModel = (Model)model.getPackagedElements().get(0); |
| assertEquals(0, subModel.getPackagedElements().size()); |
| assertEquals(1, subModel.getAppliedProfiles().size()); |
| // @formatter:on |
| |
| // Checks the content of the left model after merging |
| assertEqualsM6(left); |
| } |
| |
| /** |
| * Tests advanced use case: |
| * <ol> |
| * <li>Creates a {@link StereotypedElementChange} of kind {@link DifferenceKind#ADD} with dependencies |
| * (requires creation of parent + profile application)</li> |
| * <li>Merges it from right to left</li> |
| * </ol> |
| * <p> |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `--<b> <Model> MyNiceModel |
| * `-- <<ACliche>> <Class> Class1 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class1]</b> |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * </pre> |
| * |
| * <h4>Expected left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `--<b> <Model> MyNiceModel |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * </p> |
| * |
| * @throws IOException |
| */ |
| protected void testAddStereotypedElementRToL2(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| // Checks differences |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.ADD, 2); |
| |
| assertAddedBaseElementDiff(differences, "model.MyNiceModel.Class1", stereotypedElementChange); //$NON-NLS-1$ |
| |
| // Merges |
| mergeRightToLeft(stereotypedElementChange); |
| |
| // Checks comparison model after merging |
| Set<Diff> expectedMergeDifferences = getRefinedByClosure(stereotypedElementChange); |
| for (Diff diff : differences) { |
| final DifferenceState expectedDiffState; |
| if (expectedMergeDifferences.contains(diff) || stereotypedElementChange.equals(diff)) { |
| expectedDiffState = DifferenceState.DISCARDED; |
| } else { |
| expectedDiffState = DifferenceState.UNRESOLVED; |
| } |
| assertSame(expectedDiffState, diff.getState()); |
| } |
| |
| // Checks left model content after merging |
| // @formatter:off |
| EList<EObject> contents = left.getContents(); |
| assertEquals(1, contents.size()); |
| Model model = (Model)contents.get(0); |
| assertEquals(1, model.getPackagedElements().size()); |
| Model subModel = (Model)model.getPackagedElements().get(0); |
| assertEquals(0, subModel.getPackagedElements().size()); |
| assertEquals(1, subModel.getAppliedProfiles().size()); |
| // @formatter:on |
| |
| // Checks right model content after merging |
| assertEqualsM6(right); |
| } |
| |
| /** |
| * Tests advanced use case: |
| * <ol> |
| * <li>Creates a {@link StereotypedElementChange} of kind {@link DifferenceKind#DELL} with dependencies |
| * </li> |
| * <li>Merges it from right to left</li> |
| * </ol> |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `--<b> <Model> MyNiceModel |
| * `-- <<ACliche>> <Class> Class1 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class1]</b> |
| * </pre> |
| * |
| * <h4>Expected left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Model> MyNiceModel |
| * `-- <<ACliche>> <Class> Class1 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class1] |
| * </pre> |
| * </p> |
| * |
| * @throws IOException |
| */ |
| protected void testDelStereotypedElementRToL2(Resource left, Resource right) throws IOException { |
| |
| final Comparison comparison = compare(left, right); |
| |
| // Checks model structure |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.DELETE, 2); |
| |
| assertDeletedBaseElementDiff(differences, "model.MyNiceModel.Class1", stereotypedElementChange); //$NON-NLS-1$ |
| // Merges |
| mergeRightToLeft(stereotypedElementChange); |
| |
| // Check comparison model |
| // Everything should be merged |
| for (Diff diff : differences) { |
| assertTrue(isInTerminalState(diff)); |
| } |
| |
| // Checks left model content after merging |
| assertEqualsM3(left); |
| |
| // Checks right model content after merging |
| assertEqualsM3(right); |
| |
| } |
| |
| /** |
| * Tests to merge a {@link StereotypedElementChange} of kind ADD with 2 stereotypes being applied from |
| * left to right. |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `--<b> <<ACliche, ACliche3>> <Class> Class0</b> |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche, ACliche3>> <Class> Class0]</b> |
| * <b>ACliche3 [base <<ACliche, ACliche3>> <Class> Class0]</b> |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * |
| * <h4>Expected right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche, ACliche3>> <Class> Class0 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche, ACliche3>> <Class> Class0] |
| * ACliche3 [base <<ACliche, ACliche3>> <Class> Class0] |
| * </pre> |
| * </p> |
| * |
| * @param left |
| * @param right |
| */ |
| protected void testAddMultipleStereotypesLToR(Resource left, Resource right) { |
| final Comparison comparison = compare(left, right); |
| |
| // Checks differences |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.ADD, 3); |
| |
| assertAddedBaseElementDiff(differences, "model.Class0", stereotypedElementChange); //$NON-NLS-1$ |
| |
| // Merges |
| mergeLeftToRight(stereotypedElementChange); |
| |
| // Checks comparison model after merging |
| for (Diff diff : differences) { |
| assertSame(DifferenceState.MERGED, diff.getState()); |
| } |
| |
| // Checks right model content after merging |
| assertEqualsM7(right); |
| |
| // Checks left model content after merging |
| assertEqualsM7(left); |
| |
| } |
| |
| /** |
| * Tests to merge of a {@link StereotypedElementChange} of kind ADD with 2 stereotypes being applied from |
| * right to left. |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <b><<ACliche, ACliche3>> <Class> Class0</b> |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche, ACliche3>> <Class> Class0]</b> |
| * <b>ACliche3 [base <<ACliche, ACliche3>> <Class> Class0]</b> |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * |
| * <h4>Expected left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * |
| * @param left |
| * @param right |
| */ |
| protected void testAddMultipleStereotypesRToL(Resource left, Resource right) { |
| final Comparison comparison = compare(left, right); |
| |
| // Checks differences |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.ADD, 3); |
| |
| assertAddedBaseElementDiff(differences, "model.Class0", stereotypedElementChange); //$NON-NLS-1$ |
| |
| // Merges |
| mergeRightToLeft(stereotypedElementChange); |
| |
| // Check comparison model |
| for (Diff diff : differences) { |
| assertTrue(isInTerminalState(diff)); |
| } |
| |
| // Checks left model content after merging |
| assertEqualsM2(left); |
| |
| // Checks right model content after merging |
| assertEqualsM2(right); |
| |
| } |
| |
| /** |
| * Tests to merge a {@link StereotypedElementChange} of kind DELETE in conflict with another diff from |
| * right to left. |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <b><<ACliche, ACliche3>> <Class> Class0_newName</b> |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche, ACliche3>> <Class> Class0_newName]</b> |
| * <b>ACliche3 [base <<ACliche, ACliche3>> <Class> Class0_newName]</b> |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * |
| * <h4>Ancestor model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche, ACliche3>> <Class> Class0 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche, ACliche3>> <Class> Class0] |
| * ACliche3 [base <<ACliche, ACliche3>> <Class> Class0] |
| * </pre> |
| * |
| * <h4>Expected left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * </p> |
| * |
| * @param left |
| * @param right |
| * @param origin |
| */ |
| protected void testDelConflictRToL(Resource left, Resource right, Resource origin) { |
| final Comparison comparison = compare(left, right, origin); |
| |
| // Checks differences |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.DELETE, 3); |
| |
| final ReferenceChange baseDiff = assertDeletedBaseElementDiff(differences, "model.Class0", //$NON-NLS-1$ |
| stereotypedElementChange); |
| |
| // the stereotype change itself is not in a conflict |
| assertNull(stereotypedElementChange.getConflict()); |
| |
| // but one of its refining diffs is in exactly one conflict |
| final Set<Conflict> conflicts = getConflictsOfRefiningDiffs(stereotypedElementChange); |
| final Conflict conflict = Iterables.getOnlyElement(conflicts); |
| |
| assertNotNull(conflict); |
| assertEquals(2, conflict.getDifferences().size()); |
| |
| final EList<Diff> leftDifferences = conflict.getLeftDifferences(); |
| assertEquals(1, leftDifferences.size()); |
| |
| final Diff leftDiff = leftDifferences.get(0); |
| assertTrue(leftDiff instanceof AttributeChange); |
| assertEquals(1, conflict.getRightDifferences().size()); |
| assertTrue(conflict.getRightDifferences().contains(baseDiff)); |
| |
| // Merges |
| mergeRightToLeft(stereotypedElementChange); |
| |
| for (Diff diff : differences) { |
| assertTrue(isInTerminalState(diff)); |
| } |
| // Checks left model content after merging |
| assertEqualsM2(left); |
| |
| // Checks right model content after merging |
| assertEqualsM2(right); |
| |
| } |
| |
| /** |
| * Tests to merge a {@link StereotypedElementChange} of kind DELETE in conflict with another diff from |
| * left to right. |
| * <p> |
| * <h3>Inputs</h3> |
| * <h4>Left model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <b><<ACliche, ACliche3>> <Class> Class0_newName</b> |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * <b>ACliche [base <<ACliche, ACliche3>> <Class> Class0_newName]</b> |
| * <b>ACliche3 [base <<ACliche, ACliche3>> <Class> Class0_newName]</b> |
| * </pre> |
| * |
| * <h4>Right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * |
| * <h4>Ancestor model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche, ACliche3>> <Class> Class0 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche, ACliche3>> <Class> Class0] |
| * ACliche3 [base <<ACliche, ACliche3>> <Class> Class0] |
| * </pre> |
| * |
| * <h4>Expected right model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche, ACliche3>> <Class> Class0_newName |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche, ACliche3>> <Class> Class0_newName] |
| * ACliche3 [base <<ACliche, ACliche3>> <Class> Class0_newName] |
| * </pre> |
| * </p> |
| * |
| * @param left |
| * @param right |
| * @param origin |
| */ |
| protected void testAbstractDelConflictLToR(Resource left, Resource right, Resource origin) { |
| final Comparison comparison = compare(left, right, origin); |
| |
| // Checks model structure |
| final EList<Diff> differences = comparison.getDifferences(); |
| final StereotypedElementChange stereotypedElementChange = getStereotypedElementChange(differences, |
| DifferenceKind.DELETE, 3); |
| |
| final ReferenceChange baseDiff = assertDeletedBaseElementDiff(differences, "model.Class0", //$NON-NLS-1$ |
| stereotypedElementChange); |
| |
| // the stereotype change itself is not in a conflict |
| assertNull(stereotypedElementChange.getConflict()); |
| |
| // but one of its refining diffs is in exactly one conflict |
| final Set<Conflict> conflicts = getConflictsOfRefiningDiffs(stereotypedElementChange); |
| final Conflict conflict = Iterables.getOnlyElement(conflicts); |
| assertEquals(2, conflict.getDifferences().size()); |
| |
| final EList<Diff> leftDifferences = conflict.getLeftDifferences(); |
| assertEquals(1, leftDifferences.size()); |
| |
| final Diff leftConflictDiff = leftDifferences.get(0); |
| |
| assertTrue(leftConflictDiff instanceof AttributeChange); |
| assertEquals(1, conflict.getRightDifferences().size()); |
| assertTrue(conflict.getRightDifferences().contains(baseDiff)); |
| // Merges |
| mergeLeftToRight(stereotypedElementChange); |
| |
| for (Diff diff : differences) { |
| if (leftConflictDiff.equals(diff)) { |
| assertSame(DifferenceState.UNRESOLVED, diff.getState()); |
| } else { |
| assertSame(DifferenceState.DISCARDED, diff.getState()); |
| } |
| } |
| |
| // Checks right model content after merging |
| assertEqualsM4(right); |
| |
| // Checks left model content after merging |
| assertEqualsM5(left); |
| |
| } |
| |
| /** |
| * Returns the conflicts of the refining diffs of the given {@code refinedDiff}. |
| * |
| * @param refinedDiff |
| * The refined diff to get the conflicts from. |
| * @return the list of conflicts. |
| */ |
| private Set<Conflict> getConflictsOfRefiningDiffs(Diff refinedDiff) { |
| Builder<Conflict> builder = ImmutableSet.builder(); |
| for (Diff refiningDiff : refinedDiff.getRefinedBy()) { |
| if (refiningDiff.getConflict() != null) { |
| builder.add(refiningDiff.getConflict()); |
| } |
| } |
| return builder.build(); |
| } |
| |
| /** |
| * Checks that the input has the same structure than described bellow: |
| * <p> |
| * <h4>Expected model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche>> <Class> Class0 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class0] |
| * </pre> |
| * </p> |
| * |
| * @param input |
| */ |
| private void assertEqualsM1(final Resource input) { |
| // @formatter:off |
| EList<EObject> contents = input.getContents(); |
| assertEquals(2, contents.size()); |
| Model model = (Model)contents.get(0); |
| assertEquals(1, model.getPackagedElements().size()); |
| Class clazz = (Class)model.getPackagedElements().get(0); |
| assertEquals(1, clazz.getAppliedStereotypes().size()); |
| assertEquals(1, model.getAppliedProfiles().size()); |
| EObject stereotypeApplication = contents.get(1); |
| assertSame(clazz, UMLUtil.getBaseElement(stereotypeApplication)); |
| // @formatter:on |
| } |
| |
| /** |
| * Checks that the input has the same structure than described bellow: |
| * <p> |
| * <h4>Expected model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * </pre> |
| * </p> |
| * |
| * @param input |
| */ |
| private void assertEqualsM2(final Resource input) { |
| // @formatter:off |
| EList<EObject> contents = input.getContents(); |
| assertEquals(1, contents.size()); |
| Model model = (Model)contents.get(0); |
| assertEquals(0, model.getPackagedElements().size()); |
| assertEquals(1, model.getAppliedProfiles().size()); |
| // @formatter:on |
| } |
| |
| /** |
| * Checks that the input has the same structure than described bellow: |
| * <p> |
| * <h4>Expected model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <Model> MyNiceModel |
| * `-- <<ACliche>> <Class> Class1 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche>> <Class> Class1] |
| * </pre> |
| * </p> |
| * |
| * @param input |
| */ |
| private void assertEqualsM3(Resource input) { |
| // @formatter:off |
| EList<EObject> contents = input.getContents(); |
| assertEquals(2, contents.size()); |
| Model model = (Model)contents.get(0); |
| assertEquals(1, model.getPackagedElements().size()); |
| Model subModel = (Model)model.getPackagedElements().get(0); |
| assertEquals(1, subModel.getPackagedElements().size()); |
| Class clazz = (Class)subModel.getPackagedElements().get(0); |
| assertEquals(1, clazz.getAppliedStereotypes().size()); |
| assertEquals(1, subModel.getAppliedProfiles().size()); |
| EObject stereotypeApplication = contents.get(1); |
| assertSame(clazz, UMLUtil.getBaseElement(stereotypeApplication)); |
| // @formatter:on |
| } |
| |
| /** |
| * Checks that the input has the same structure than described bellow: |
| * <p> |
| * <h4>Expected model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche, ACliche3>> <Class> Class0_newName |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche, ACliche3>> <Class> Class0_newName] |
| * ACliche3 [base <<ACliche, ACliche3>> <Class> Class0_newName] |
| * </pre> |
| * </p> |
| * |
| * @param input |
| */ |
| private void assertEqualsM4(Resource right) { |
| // @formatter:off |
| EList<EObject> contents = right.getContents(); |
| assertEquals(3, contents.size()); |
| Model model = (Model)contents.get(0); |
| assertEquals(1, model.getPackagedElements().size()); |
| Class clazz = (Class)model.getPackagedElements().get(0); |
| assertEquals(2, clazz.getAppliedStereotypes().size()); |
| assertEquals("Class0", clazz.getName()); //$NON-NLS-1$ |
| assertEquals(1, model.getAppliedProfiles().size()); |
| EObject stereotypeApplication = contents.get(1); |
| assertSame(clazz, UMLUtil.getBaseElement(stereotypeApplication)); |
| EObject stereotypeApplication2 = contents.get(2); |
| assertSame(clazz, UMLUtil.getBaseElement(stereotypeApplication2)); |
| // @formatter:on |
| } |
| |
| /** |
| * Checks that the input has the same structure than described bellow: |
| * <p> |
| * <h4>Expected model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche, ACliche3>> <Class> Class0_newName |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche, ACliche3>> <Class> Class0_newName] |
| * ACliche3 [base <<ACliche, ACliche3>> <Class> Class0_newName] |
| * </pre> |
| * </p> |
| * |
| * @param input |
| */ |
| private void assertEqualsM5(Resource right) { |
| // @formatter:off |
| EList<EObject> contents = right.getContents(); |
| assertEquals(3, contents.size()); |
| Model model = (Model)contents.get(0); |
| assertEquals(1, model.getPackagedElements().size()); |
| Class clazz = (Class)model.getPackagedElements().get(0); |
| assertEquals(2, clazz.getAppliedStereotypes().size()); |
| assertEquals("Class0_newName", clazz.getName()); //$NON-NLS-1$ |
| assertEquals(1, model.getAppliedProfiles().size()); |
| EObject stereotypeApplication = contents.get(1); |
| assertSame(clazz, UMLUtil.getBaseElement(stereotypeApplication)); |
| EObject stereotypeApplication2 = contents.get(2); |
| assertSame(clazz, UMLUtil.getBaseElement(stereotypeApplication2)); |
| // @formatter:on |
| } |
| |
| /** |
| * Checks that the input has the same structure than described bellow: |
| * <p> |
| * <h4>Expected model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * </pre> |
| * </p> |
| * |
| * @param input |
| */ |
| private void assertEqualsM6(Resource input) { |
| // @formatter:off |
| EList<EObject> leftContent = input.getContents(); |
| assertEquals(1, leftContent.size()); |
| Model leftModel = (Model)leftContent.get(0); |
| assertEquals(0, leftModel.getPackagedElements().size()); |
| assertEquals(0, leftModel.getAppliedProfiles().size()); |
| // @formatter:on |
| } |
| |
| /** |
| * Checks that the input has the same structure than described bellow: |
| * <p> |
| * <h4>Expected model</h4> |
| * |
| * <pre> |
| * <Model> model |
| * `-- <<ACliche, ACliche3>> <Class> Class0 |
| * `-- <Profile Application> UML2CompareTestProfile |
| * `-- UML |
| * ACliche [base <<ACliche, ACliche3>> <Class> Class0] |
| * ACliche3 [base <<ACliche, ACliche3>> <Class> Class0] |
| * </pre> |
| * </p> |
| * |
| * @param input |
| */ |
| private void assertEqualsM7(Resource inputs) { |
| // @formatter:off |
| EList<EObject> contents = inputs.getContents(); |
| assertEquals(3, contents.size()); |
| Model model = (Model)contents.get(0); |
| assertEquals(1, model.getPackagedElements().size()); |
| Class clazz = (Class)model.getPackagedElements().get(0); |
| assertEquals(2, clazz.getAppliedStereotypes().size()); |
| assertEquals(1, model.getAppliedProfiles().size()); |
| EObject stereotypeApplication = contents.get(1); |
| assertSame(clazz, UMLUtil.getBaseElement(stereotypeApplication)); |
| EObject stereotypeApplication2 = contents.get(2); |
| assertSame(clazz, UMLUtil.getBaseElement(stereotypeApplication2)); |
| // @formatter:on |
| } |
| |
| private StereotypedElementChange getStereotypedElementChange(final EList<Diff> differences, |
| DifferenceKind diffKind, int expectedRefine) { |
| Iterable<StereotypedElementChange> stereotypesChanges = getStereotypedElementChanges(differences, |
| diffKind); |
| assertEquals(1, Iterables.size(stereotypesChanges)); |
| final StereotypedElementChange stereotypedElementChange = stereotypesChanges.iterator().next(); |
| assertSame(diffKind, stereotypedElementChange.getKind()); |
| assertEquals(expectedRefine, stereotypedElementChange.getRefinedBy().size()); |
| return stereotypedElementChange; |
| } |
| |
| /** |
| * Gets the closure of the refined by elements from a starting diff. |
| * |
| * @param startingDiff |
| * @return |
| */ |
| private Set<Diff> getRefinedByClosure(Diff startingDiff) { |
| Set<Diff> result = new HashSet<Diff>(); |
| for (Diff refinedByDiff : startingDiff.getRefinedBy()) { |
| if (!result.contains(refinedByDiff)) { |
| getRefinedByClosure(refinedByDiff, result); |
| } |
| } |
| return result; |
| } |
| |
| private void getRefinedByClosure(Diff d, Set<Diff> result) { |
| result.add(d); |
| for (Diff refinedByDiff : d.getRefinedBy()) { |
| if (!result.contains(refinedByDiff)) { |
| getRefinedByClosure(refinedByDiff, result); |
| } |
| } |
| } |
| |
| protected void mergeLeftToRight(Diff difference) { |
| BatchMerger merger = new BatchMerger(getMergerRegistry()); |
| merger.copyAllLeftToRight(Collections.singleton(difference), new BasicMonitor()); |
| } |
| |
| protected void mergeRightToLeft(Diff difference) { |
| BatchMerger merger = new BatchMerger(getMergerRegistry()); |
| merger.copyAllRightToLeft(Collections.singleton(difference), new BasicMonitor()); |
| } |
| |
| private ReferenceChange assertAddedBaseElementDiff(Iterable<Diff> differences, String qualifiedName, |
| StereotypedElementChange stereotypedElementChange) { |
| ReferenceChange referenceChange = (ReferenceChange)Iterables.find(differences, added(qualifiedName)); |
| assertTrue(stereotypedElementChange.getRefinedBy().contains(referenceChange)); |
| assertSame(referenceChange.getValue(), stereotypedElementChange.getDiscriminant()); |
| return referenceChange; |
| } |
| |
| private ReferenceChange assertDeletedBaseElementDiff(Iterable<Diff> differences, String qualifiedName, |
| StereotypedElementChange stereotypedElementChange) { |
| ReferenceChange referenceChange = (ReferenceChange)Iterables.find(differences, |
| removed(qualifiedName)); |
| assertTrue(stereotypedElementChange.getRefinedBy().contains(referenceChange)); |
| assertSame(referenceChange.getValue(), stereotypedElementChange.getDiscriminant()); |
| return referenceChange; |
| } |
| |
| /** |
| * Gets the {@link StereotypedElementChange}s contained in the input differences. |
| * |
| * @param differences |
| * Input differences. |
| * @param diffKind |
| * Kind of difference you are looking for. |
| * @return |
| */ |
| private Iterable<StereotypedElementChange> getStereotypedElementChanges(Iterable<Diff> differences, |
| DifferenceKind diffKind) { |
| final Predicate<Diff> selectingPredicate = and(instanceOf(StereotypedElementChange.class), |
| ofKind(diffKind)); |
| return Iterables.transform(Iterables.filter(differences, selectingPredicate), |
| new Function<Diff, StereotypedElementChange>() { |
| |
| public StereotypedElementChange apply(Diff input) { |
| return (StereotypedElementChange)input; |
| } |
| }); |
| } |
| |
| } |