/** * Copyright (c) 2016, 2017 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 * Martin Fleck - bug 512562 */ package org.eclipse.emf.compare.ide.ui.tests.unit; import static com.google.common.collect.Iterables.filter; import static org.eclipse.emf.compare.utils.EMFComparePredicates.onEObject; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.Collections; import org.eclipse.compare.ITypedElement; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IStorage; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.compare.Comparison; import org.eclipse.emf.compare.Diff; import org.eclipse.emf.compare.EMFCompare; import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIPlugin; import org.eclipse.emf.compare.ide.ui.internal.logical.ComparisonScopeBuilder; import org.eclipse.emf.compare.ide.ui.internal.logical.StorageTypedElement; import org.eclipse.emf.compare.ide.ui.internal.logical.StreamAccessorStorage; import org.eclipse.emf.compare.ide.ui.internal.util.PlatformElementUtil; import org.eclipse.emf.compare.ide.ui.logical.IModelResolver; import org.eclipse.emf.compare.ide.ui.tests.CompareTestCase; import org.eclipse.emf.compare.ide.utils.ResourceUtil; import org.eclipse.emf.compare.merge.BatchMerger; import org.eclipse.emf.compare.rcp.EMFCompareRCPPlugin; import org.eclipse.emf.compare.scope.IComparisonScope; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.EcoreUtil; import org.junit.Test; import org.osgi.framework.Bundle; @SuppressWarnings({"restriction", "nls" }) public class TestBug497566 extends CompareTestCase { /** * Uncontrol an element. The element uncontrolled is in a fragment in the right and origin resources. The * element is in the root resource in the left resource (no fragment on the left side). After the merge, * the right fragment is empty. * * @throws IOException * @throws CoreException * @throws URISyntaxException */ @Test public void testUncontrolElementCausesEmptyFragment() throws IOException, CoreException, URISyntaxException { IComparisonScope scope = initComparison("_497566/empty"); Comparison comparison = EMFCompare.builder().build().compare(scope); BatchMerger batchMerger = new BatchMerger(EMFCompareRCPPlugin.getDefault().getMergerRegistry()); ResourceSet leftResourceSet = (ResourceSet)scope.getLeft(); ResourceSet rightResourceSet = (ResourceSet)scope.getRight(); ResourceSet originResourceSet = (ResourceSet)scope.getOrigin(); EcoreUtil.resolveAll(leftResourceSet); EcoreUtil.resolveAll(rightResourceSet); EcoreUtil.resolveAll(originResourceSet); assertEquals(1, leftResourceSet.getResources().size()); assertEquals(2, rightResourceSet.getResources().size()); assertEquals(rightResourceSet.getResources().get(0).getURI().lastSegment(), "right.nodes"); assertEquals(rightResourceSet.getResources().get(1).getURI().lastSegment(), "fragment.nodes"); assertEquals(2, originResourceSet.getResources().size()); batchMerger.copyAllLeftToRight(comparison.getDifferences(), null); ResourceUtil.saveAllResources(leftResourceSet, Collections.emptyMap()); ResourceUtil.saveAllResources(rightResourceSet, Collections.emptyMap()); ResourceUtil.saveAllResources(originResourceSet, Collections.emptyMap()); // After merge, the right fragment is empty so it has been deleted in the right resourceSet assertEquals(1, leftResourceSet.getResources().size()); assertEquals(1, rightResourceSet.getResources().size()); assertEquals(rightResourceSet.getResources().get(0).getURI().lastSegment(), "right.nodes"); assertEquals(2, originResourceSet.getResources().size()); // The right fragment (file) must have also been deleted from the file system IResource fragmentFile = ResourcesPlugin.getWorkspace().getRoot() .findMember("Project-1/right/fragment.nodes"); assertNull(fragmentFile); } /** * Uncontrol an element. The element uncontrolled is in a fragment in the right and origin resources. The * element is in the root resource in the left resource (no fragment on the left side). After the merge, * the right fragment is not empty, because it is not the only root element in the fragment. * * @throws IOException * @throws CoreException * @throws URISyntaxException */ @Test public void testUncontrolElementCausesNotEmptyFragment() throws IOException, CoreException, URISyntaxException { IComparisonScope scope = initComparison("_497566/notempty"); Comparison comparison = EMFCompare.builder().build().compare(scope); BatchMerger batchMerger = new BatchMerger(EMFCompareRCPPlugin.getDefault().getMergerRegistry()); ResourceSet leftResourceSet = (ResourceSet)scope.getLeft(); ResourceSet rightResourceSet = (ResourceSet)scope.getRight(); ResourceSet originResourceSet = (ResourceSet)scope.getOrigin(); EcoreUtil.resolveAll(leftResourceSet); EcoreUtil.resolveAll(rightResourceSet); EcoreUtil.resolveAll(originResourceSet); assertEquals(1, leftResourceSet.getResources().size()); assertEquals(2, rightResourceSet.getResources().size()); assertEquals(rightResourceSet.getResources().get(0).getURI().lastSegment(), "right.nodes"); assertEquals(rightResourceSet.getResources().get(1).getURI().lastSegment(), "fragment.nodes"); assertEquals(2, originResourceSet.getResources().size()); EList<Diff> differences = comparison.getDifferences(); Iterable<Diff> filter2 = filter(differences, onEObject("root.fragmented")); batchMerger.copyAllLeftToRight(filter2, null); ResourceUtil.saveAllResources(leftResourceSet, Collections.emptyMap()); ResourceUtil.saveAllResources(rightResourceSet, Collections.emptyMap()); ResourceUtil.saveAllResources(originResourceSet, Collections.emptyMap()); // After merge, the right fragment is not empty so it has not been deleted in the right resourceSet assertEquals(1, leftResourceSet.getResources().size()); assertEquals(2, rightResourceSet.getResources().size()); assertEquals(2, originResourceSet.getResources().size()); // The right fragment (file) must have also been deleted from the file system IResource fragmentFile = ResourcesPlugin.getWorkspace().getRoot() .findMember("Project-1/right/fragment.nodes"); assertNotNull(fragmentFile); } /** * Uncontrol elements. The elements uncontrolled are in a fragment in the right and origin resources. The * elements are in the root resource in the left resource (no fragment on the left side). After the merge * of the first root fragment element, the right fragment is not empty, because it is not the only root * element in the fragment. After the second merge, the right fragment becomes empty. * * @throws IOException * @throws CoreException * @throws URISyntaxException */ @Test public void testUncontrolElementsCausesEmptyFragmentAfterMultipleMerge() throws IOException, CoreException, URISyntaxException { IComparisonScope scope = initComparison("_497566/empty2"); Comparison comparison = EMFCompare.builder().build().compare(scope); BatchMerger batchMerger = new BatchMerger(EMFCompareRCPPlugin.getDefault().getMergerRegistry()); ResourceSet leftResourceSet = (ResourceSet)scope.getLeft(); ResourceSet rightResourceSet = (ResourceSet)scope.getRight(); ResourceSet originResourceSet = (ResourceSet)scope.getOrigin(); EcoreUtil.resolveAll(leftResourceSet); EcoreUtil.resolveAll(rightResourceSet); EcoreUtil.resolveAll(originResourceSet); assertEquals(1, leftResourceSet.getResources().size()); assertEquals(2, rightResourceSet.getResources().size()); assertEquals(rightResourceSet.getResources().get(0).getURI().lastSegment(), "right.nodes"); assertEquals(rightResourceSet.getResources().get(1).getURI().lastSegment(), "fragment.nodes"); assertEquals(2, originResourceSet.getResources().size()); EList<Diff> differences = comparison.getDifferences(); Iterable<Diff> filter2 = filter(differences, onEObject("root.fragmented")); batchMerger.copyAllLeftToRight(filter2, null); ResourceUtil.saveAllResources(leftResourceSet, Collections.emptyMap()); ResourceUtil.saveAllResources(rightResourceSet, Collections.emptyMap()); ResourceUtil.saveAllResources(originResourceSet, Collections.emptyMap()); // After the first merge , the right fragment is not empty so it has not been deleted in the right // resourceSet assertEquals(1, leftResourceSet.getResources().size()); assertEquals(2, rightResourceSet.getResources().size()); assertEquals(2, originResourceSet.getResources().size()); // The right fragment (file) must have also been deleted from the file system IResource fragmentFile = ResourcesPlugin.getWorkspace().getRoot() .findMember("Project-1/right/fragment.nodes"); assertNotNull(fragmentFile); // 2nd merge comparison = EMFCompare.builder().build().compare(scope); EcoreUtil.resolveAll(leftResourceSet); EcoreUtil.resolveAll(rightResourceSet); EcoreUtil.resolveAll(originResourceSet); assertEquals(1, leftResourceSet.getResources().size()); assertEquals(2, rightResourceSet.getResources().size()); assertEquals(rightResourceSet.getResources().get(0).getURI().lastSegment(), "right.nodes"); assertEquals(rightResourceSet.getResources().get(1).getURI().lastSegment(), "fragment.nodes"); assertEquals(2, originResourceSet.getResources().size()); batchMerger.copyAllLeftToRight(comparison.getDifferences(), null); ResourceUtil.saveAllResources(leftResourceSet, Collections.emptyMap()); ResourceUtil.saveAllResources(rightResourceSet, Collections.emptyMap()); ResourceUtil.saveAllResources(originResourceSet, Collections.emptyMap()); // After the last merge, the right fragment is empty so it has been deleted in the right resourceSet assertEquals(1, leftResourceSet.getResources().size()); assertEquals(1, rightResourceSet.getResources().size()); assertEquals(rightResourceSet.getResources().get(0).getURI().lastSegment(), "right.nodes"); assertEquals(2, originResourceSet.getResources().size()); // The right fragment (file) must have also been deleted from the file system fragmentFile = ResourcesPlugin.getWorkspace().getRoot().findMember("Project-1/right/fragment.nodes"); assertNull(fragmentFile); } private IComparisonScope initComparison(String projectName) throws IOException, CoreException, URISyntaxException { final IProject iProject = project.getProject(); final File leftFile1 = project.getOrCreateFile(iProject, "left/left.nodes"); final File rightFile1 = project.getOrCreateFile(iProject, "right/right.nodes"); final File rightFragment1 = project.getOrCreateFile(iProject, "right/fragment.nodes"); final File originFile1 = project.getOrCreateFile(iProject, "origin/origin.nodes"); final File originFragment1 = project.getOrCreateFile(iProject, "origin/fragment.nodes"); Bundle bundle = Platform.getBundle("org.eclipse.emf.compare.ide.ui.tests"); IFile iLeftFile1 = project.getIFile(iProject, leftFile1); copy(testPath(projectName + "/left/left.nodes"), iLeftFile1, bundle); IFile iRightFile1 = project.getIFile(iProject, rightFile1); copy(testPath(projectName + "/right/right.nodes"), iRightFile1, bundle); IFile iRightFragmentFile1 = project.getIFile(iProject, rightFragment1); copy(testPath(projectName + "/right/fragment.nodes"), iRightFragmentFile1, bundle); IFile iOriginFile1 = project.getIFile(iProject, originFile1); copy(testPath(projectName + "/origin/origin.nodes"), iOriginFile1, bundle); IFile iOriginFragmentFile1 = project.getIFile(iProject, originFragment1); copy(testPath(projectName + "/origin/fragment.nodes"), iOriginFragmentFile1, bundle); final ITypedElement left = new StorageTypedElement(iLeftFile1, iLeftFile1.getFullPath().toString()); final ITypedElement right = new StorageTypedElement(iRightFile1, iRightFile1.getFullPath().toString()); final ITypedElement origin = new StorageTypedElement(iOriginFile1, iOriginFile1.getFullPath().toString()); IStorage leftStorage = PlatformElementUtil.findFile(left); if (leftStorage == null) { leftStorage = StreamAccessorStorage.fromTypedElement(left); } final IModelResolver resolver = EMFCompareIDEUIPlugin.getDefault().getModelResolverRegistry() .getBestResolverFor(leftStorage); final ComparisonScopeBuilder scopeBuilder = new ComparisonScopeBuilder(resolver, EMFCompareIDEUIPlugin.getDefault().getModelMinimizerRegistry().getCompoundMinimizer(), null); final IComparisonScope scope = scopeBuilder.build(left, right, origin, new NullProgressMonitor()); return scope; } protected void copy(IPath from, IFile target, Bundle bundle) throws CoreException, IOException { target.setContents(FileLocator.openStream(bundle, from, false), true, false, null); } protected Path testPath(String dataRelativePath) { return new Path("src/org/eclipse/emf/compare/ide/ui/tests/unit/data/" + dataRelativePath); } }