/******************************************************************************* * Copyright (c) 2016 EclipseSource Services GmbH and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Martin Fleck - initial API and implementation *******************************************************************************/ package org.eclipse.emf.compare.ide.ui.tests.structuremergeviewer.actions; import static com.google.common.collect.Iterables.all; import static com.google.common.collect.Iterables.any; import static org.eclipse.emf.compare.ConflictKind.REAL; import static org.eclipse.emf.compare.DifferenceState.UNRESOLVED; import static org.eclipse.emf.compare.merge.AbstractMerger.SUB_DIFF_AWARE_OPTION; import static org.eclipse.emf.compare.utils.EMFComparePredicates.containsConflictOfTypes; import static org.eclipse.emf.compare.utils.EMFComparePredicates.hasState; import static org.junit.Assert.assertTrue; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.eclipse.emf.compare.Comparison; import org.eclipse.emf.compare.Conflict; import org.eclipse.emf.compare.Diff; import org.eclipse.emf.compare.ide.ui.tests.framework.RuntimeTestRunner; import org.eclipse.emf.compare.ide.ui.tests.framework.annotations.Compare; import org.eclipse.emf.compare.ide.ui.tests.framework.internal.CompareTestSupport; import org.eclipse.emf.compare.internal.merge.MergeDependenciesUtil; import org.eclipse.emf.compare.merge.IMergeOptionAware; import org.eclipse.emf.compare.merge.IMerger; import org.eclipse.emf.compare.rcp.EMFCompareRCPPlugin; import org.junit.runner.RunWith; /** * This class tests the influence of the cascading differences filter on the merging of refinement * differences. The expectation is that refining and refined differences can only be merged together, * independent of the filter setting. * * @author Martin Fleck <mfleck@eclipsesource.com> */ @SuppressWarnings({"restriction", "nls" }) @RunWith(RuntimeTestRunner.class) public class CascadingFilterRefinementTest { private static final boolean MERGE_RIGHT_TO_LEFT = true; private static final Map<IMergeOptionAware, Object> CACHED_SUBDIFF_OPTIONS = Maps.newHashMap(); private static final IMerger.Registry MERGER_REGISTRY = EMFCompareRCPPlugin.getDefault() .getMergerRegistry(); public void enableCascadingFilter() { setCascadingFilter(true); } public void disableCascadingFilter() { setCascadingFilter(false); } public void setCascadingFilter(boolean enabled) { for (IMergeOptionAware merger : Iterables.filter(MERGER_REGISTRY.getMergers(null), IMergeOptionAware.class)) { Map<Object, Object> mergeOptions = merger.getMergeOptions(); Object previousValue = mergeOptions.get(SUB_DIFF_AWARE_OPTION); CACHED_SUBDIFF_OPTIONS.put(merger, previousValue); mergeOptions.put(SUB_DIFF_AWARE_OPTION, Boolean.valueOf(enabled)); } } public void restoreCascadingFilter() { // restore previous values for (Entry<IMergeOptionAware, Object> entry : CACHED_SUBDIFF_OPTIONS.entrySet()) { IMergeOptionAware merger = entry.getKey(); merger.getMergeOptions().put(SUB_DIFF_AWARE_OPTION, entry.getValue()); } } /** * <p> * Tests whether refining/refined diffs are only merged together when the cascading filter is enabled. * Input model: * </p> * <ul> * <li>Origin: Package 'Package1' containing class 'Class1'</li> * <li>Left: Package 'Package1' (class 'Class1' removed)</li> * <li>Right: Package 'Package1' containing class 'Class1' and class 'Class2' subclassing class 'Class1' * (class 'Class2' and generalization added) * </ul> * <p> * In the comparison, we detect a conflict between adding the generalization and the deletion of class * 'Class1'. The generalization (DirectRelationshipChange) is a refinement of adding the generalization to * 'Class2' and setting the generalizations 'general' property to the super class 'Class1'. * </p> * * @see #testRefinement_NoCascadingFilter(Comparison, CompareTestSupport) */ @Compare(left = "data/filter/cascading/left.uml", right = "data/filter/cascading/right.uml", ancestor = "data/filter/cascading/ancestor.uml") public void testRefinement_CascadingFilterEnabled(final Comparison comparison) { try { final List<Diff> differences = comparison.getDifferences(); final List<Conflict> conflicts = comparison.getConflicts(); // has real conflict assertTrue(any(conflicts, containsConflictOfTypes(REAL))); // all differences are unresolved assertTrue(all(differences, hasState(UNRESOLVED))); // enable filter and check refinement enableCascadingFilter(); verifyRefinement(differences, MERGE_RIGHT_TO_LEFT); } finally { restoreCascadingFilter(); } } /** * <p> * Tests whether refining/refined diffs are only merged together when the cascading filter is disabled. * Input model: * </p> * <ul> * <li>Origin: Package 'Package1' containing class 'Class1'</li> * <li>Left: Package 'Package1' (class 'Class1' removed)</li> * <li>Right: Package 'Package1' containing class 'Class1' and class 'Class2' subclassing class 'Class1' * (class 'Class2' and generalization added) * </ul> * <p> * In the comparison, we detect a conflict between adding the generalization and the deletion of class * 'Class1'. The generalization (DirectRelationshipChange) is a refinement of adding the generalization to * 'Class2' and setting the generalizations 'general' property to the super class 'Class1'. * </p> * * @see #testRefinement_NoCascadingFilter(Comparison, CompareTestSupport) */ @Compare(left = "data/filter/cascading/left.uml", right = "data/filter/cascading/right.uml", ancestor = "data/filter/cascading/ancestor.uml") public void testRefinement_CascadingFilterDisabled(final Comparison comparison) { try { final List<Diff> differences = comparison.getDifferences(); final List<Conflict> conflicts = comparison.getConflicts(); // has real conflict assertTrue(any(conflicts, containsConflictOfTypes(REAL))); // all differences are unresolved assertTrue(all(differences, hasState(UNRESOLVED))); // enable filter and check refinement disableCascadingFilter(); verifyRefinement(differences, MERGE_RIGHT_TO_LEFT); } finally { restoreCascadingFilter(); } } /** * Verifies that the calculated resulting merges for each difference contain all refined and refining * differences, i.e., they may only be merged as a group or not at all. * * @param differences * differences to check * @param mergeRightToLeft * merge direction */ public void verifyRefinement(List<Diff> differences, boolean mergeRightToLeft) { for (Diff diff : differences) { Set<Diff> resultingMerges = MergeDependenciesUtil.getAllResultingMerges(diff, MERGER_REGISTRY, mergeRightToLeft); assertTrue("Not all refined diffs are in resulting merges.", resultingMerges.containsAll(diff.getRefines())); assertTrue("Not all refining diffs are in resulting merges.", resultingMerges.containsAll(diff.getRefinedBy())); } } }