| /******************************************************************************* |
| * Copyright (c) 2014, 2015 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.uml2.rcp.ui.tests.groups; |
| |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Predicate; |
| import com.google.common.collect.Collections2; |
| import com.google.common.collect.Iterators; |
| import com.google.common.collect.Lists; |
| import com.google.common.eventbus.EventBus; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.emf.common.notify.AdapterFactory; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.compare.Comparison; |
| import org.eclipse.emf.compare.EMFCompare; |
| import org.eclipse.emf.compare.EMFCompare.Builder; |
| import org.eclipse.emf.compare.postprocessor.IPostProcessor; |
| import org.eclipse.emf.compare.rcp.internal.extension.impl.EMFCompareBuilderConfigurator; |
| import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.StructureMergeViewerFilter; |
| import org.eclipse.emf.compare.scope.DefaultComparisonScope; |
| import org.eclipse.emf.compare.scope.IComparisonScope; |
| import org.eclipse.emf.compare.tests.nodes.Node; |
| import org.eclipse.emf.compare.tests.nodes.NodeSingleValueAttribute; |
| import org.eclipse.emf.compare.tests.nodes.NodesFactory; |
| import org.eclipse.emf.compare.tests.nodes.util.NodesResourceFactoryImpl; |
| import org.eclipse.emf.compare.uml2.tests.edit.provider.StereotypedElementItemProviderTestUtil; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; |
| import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator; |
| import org.eclipse.emf.edit.provider.ComposedAdapterFactory; |
| import org.eclipse.emf.edit.tree.TreeNode; |
| import org.eclipse.emf.edit.tree.TreePackage; |
| import org.junit.Assert; |
| import org.junit.Before; |
| |
| /** |
| * Abstract class used to test differences order the way they would be displayed in the structure merge |
| * viewer. |
| * |
| * @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a> |
| */ |
| @SuppressWarnings("restriction") |
| public abstract class AbstractDifferenceOrderTest { |
| |
| /** |
| * Resulting comparison. |
| */ |
| private Comparison comparison; |
| |
| private ECrossReferenceAdapter crossReferenceAdapter; |
| |
| private AdapterFactoryItemDelegator itemDelegator; |
| |
| protected EventBus eventBus; |
| |
| /** |
| * Predicate mocking the {@link StructureMergeViewerFilter} behavior. |
| */ |
| private Predicate<EObject> viewerFilterPredicate; |
| |
| /** |
| * {@link StructureMergeViewerFilter} use to filters elements from a {@link TreeNode}. |
| */ |
| private StructureMergeViewerFilter filter; |
| |
| @Before |
| public void before() throws IOException { |
| |
| final Collection<AdapterFactory> factories = Lists.newArrayList(); |
| /* |
| * Adds all AdapterFactories to display the tree the same way it's being displayed in the structure |
| * merge viewer. |
| */ |
| factories.addAll(getAdaptersFactory()); |
| |
| final AdapterFactory composedAdapterFactory = new ComposedAdapterFactory(factories); |
| itemDelegator = new AdapterFactoryItemDelegator(composedAdapterFactory); |
| |
| comparison = getComparison(getInput()); |
| crossReferenceAdapter = new ECrossReferenceAdapter() { |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.ECrossReferenceAdapter#isIncluded(org.eclipse.emf.ecore.EReference) |
| */ |
| @Override |
| protected boolean isIncluded(EReference eReference) { |
| return eReference == TreePackage.Literals.TREE_NODE__DATA; |
| } |
| }; |
| filter = new StructureMergeViewerFilter(new EventBus()); |
| viewerFilterPredicate = new Predicate<EObject>() { |
| public boolean apply(EObject input) { |
| AdapterImpl adapter = new AdapterImpl(); |
| adapter.setTarget(input); |
| return filter.select(null, null, adapter); |
| } |
| }; |
| |
| } |
| |
| /** |
| * Compares the expected result with the list of roots. |
| * |
| * @param expectedResult |
| * Resource holding a Nodes models. This "nodes" model represent the expected. |
| * @param actualTrees |
| * Actual trees that the viewer would display (without any filter being applied). |
| * @param testIcons |
| * Set to true if the icon of each element should be checked. |
| */ |
| protected void compareTree(Resource expectedResult, List<? extends TreeNode> actualTrees, |
| boolean testIcons) { |
| List<? extends TreeNode> nonFilteredActualRoot = Lists |
| .newArrayList(Collections2.filter(actualTrees, viewerFilterPredicate)); |
| EList<EObject> expectedContent = expectedResult.getContents(); |
| Assert.assertEquals(expectedContent.size(), nonFilteredActualRoot.size()); |
| |
| for (int i = 0; i < expectedContent.size(); i++) { |
| Node expectedRootNode = (Node)expectedContent.get(i); |
| TreeNode actualRoot = nonFilteredActualRoot.get(i); |
| TreeIterator<EObject> expectedIterator = expectedRootNode.eAllContents(); |
| // Filters elements the way the structure merge viewer would with this filter. |
| final Iterator<EObject> realIterator = Iterators.filter(actualRoot.eAllContents(), |
| viewerFilterPredicate); |
| // Compares |
| compareTree(expectedIterator, realIterator, testIcons); |
| } |
| |
| } |
| |
| private void compareTree(TreeIterator<EObject> expectedIterator, final Iterator<EObject> realIterator, |
| boolean testIcons) { |
| while (expectedIterator.hasNext()) { |
| Node expectedElement = (Node)expectedIterator.next(); |
| Assert.assertTrue("No match for element " + expectedElement.getName(), realIterator.hasNext()); //$NON-NLS-1$ |
| EObject actualElem = realIterator.next(); |
| |
| // Checks same name. |
| Assert.assertEquals(getErrorMessage(actualElem), expectedElement.getName(), |
| itemDelegator.getText(actualElem)); |
| if (testIcons) { |
| // Checks correct icon |
| Assert.assertTrue(expectedElement instanceof NodeSingleValueAttribute); |
| List<String> actualIcons = StereotypedElementItemProviderTestUtil |
| .getIconsLocation(itemDelegator.getImage(actualElem)); |
| Assert.assertEquals("Wrong icon on " + expectedElement.getName(), //$NON-NLS-1$ |
| ((NodeSingleValueAttribute)expectedElement).getSingleValuedAttribute(), |
| Joiner.on(',').join(actualIcons)); |
| } |
| if (expectedElement.eContainer() != null) { |
| final Collection<Node> expectedChildren = expectedElement.getContainmentRef1(); |
| // Checks same number of children. |
| Assert.assertEquals("Incorrect children for " + getFullPath(actualElem), //$NON-NLS-1$ |
| expectedChildren.size(), Collections2 |
| .filter(((TreeNode)actualElem).getChildren(), viewerFilterPredicate).size()); |
| } |
| } |
| } |
| |
| /** |
| * @return List of AdapterFactory used to fill the {@link AdapterFactoryItemDelegator} |
| */ |
| protected abstract List<AdapterFactory> getAdaptersFactory(); |
| |
| /** |
| * @return Input data for the comparison. |
| */ |
| protected abstract NotifierScopeProvider getInput(); |
| |
| protected Comparison getComparison() { |
| return comparison; |
| } |
| |
| /** |
| * Returns the resulting comparison. |
| * |
| * @param scopeProvider |
| * Input of the comparison. |
| * @return {@link Comparison} |
| * @throws IOException |
| */ |
| private Comparison getComparison(NotifierScopeProvider scopeProvider) throws IOException { |
| final IComparisonScope scope = new DefaultComparisonScope(scopeProvider.getLeft(), |
| scopeProvider.getRight(), scopeProvider.getOrigin()); |
| final Builder builder = EMFCompare.builder(); |
| EMFCompareBuilderConfigurator.createDefault().configure(builder); |
| return builder.build().compare(scope); |
| } |
| |
| protected ECrossReferenceAdapter getCrossReferenceAdapter() { |
| return crossReferenceAdapter; |
| } |
| |
| /** |
| * Creates a understandable error message. |
| * |
| * @param actual |
| * @return |
| */ |
| private String getErrorMessage(EObject actual) { |
| StringBuilder message = new StringBuilder(); |
| message.append("Content error on \"").append(getFullPath(actual)).append("\""); //$NON-NLS-1$ //$NON-NLS-2$ |
| return message.toString(); |
| } |
| |
| protected StructureMergeViewerFilter getFilter() { |
| return filter; |
| } |
| |
| /** |
| * Creates a String representing the full path of the element. |
| * |
| * @param eObject |
| * @return |
| */ |
| private String getFullPath(EObject eObject) { |
| final String result; |
| if (eObject != null) { |
| List<String> ancestors = new ArrayList<String>(); |
| ancestors.add(itemDelegator.getText(eObject)); |
| EObject eContainer = eObject.eContainer(); |
| while (eContainer != null) { |
| ancestors.add(itemDelegator.getText(eContainer)); |
| eContainer = eContainer.eContainer(); |
| } |
| result = Joiner.on("::").join(Lists.reverse(ancestors)); //$NON-NLS-1$ |
| |
| } else { |
| result = null; |
| } |
| return result; |
| } |
| |
| /** |
| * Gets the {@link IPostProcessor.Descriptor.Registry} to use for the comparison or null if the default |
| * registry has to be used. |
| * |
| * @return |
| */ |
| protected IPostProcessor.Descriptor.Registry<?> getPostProcessorRegistry() { |
| return null; |
| } |
| |
| // Used with TestWriterHelper for writing the expected model into a file. |
| protected AdapterFactoryItemDelegator getItemDelegator() { |
| return itemDelegator; |
| } |
| |
| /** |
| * Creates a {@link TestWriterHelper} for this test. |
| * |
| * @return |
| */ |
| protected final TestWriterHelper createTestHelper() { |
| return new TestWriterHelper(); |
| } |
| |
| /** |
| * This class aims to help the writer of the test. |
| * <p> |
| * Once the tree in the {@link StructureMergeViewerFilter} has been MANUALLY checked, this class helps to |
| * serialize it in a resource. This resources holds a "Nodes" model. It represents the tree as it is |
| * displayed in the structure merge viewer. |
| * </p> |
| * model |
| * |
| * @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a> |
| */ |
| protected final class TestWriterHelper { |
| |
| private TestWriterHelper() { |
| } |
| |
| /** |
| * Creates the expected model from a list of TreeNode. |
| * <p> |
| * This method translates a list of {@link TreeNode} into a Nodes model. This model represents the |
| * tree as it is display in the StructureMergeViewer. |
| * </p> |
| * |
| * @param fileLocation |
| * Location of newly created file will be serialized. |
| * @param roots |
| * Lists of roots to serialize in the model. |
| * @param fillIcon |
| * Set to true if the generated model should keep track of the element icons. |
| */ |
| public void createExpectedModel(String fileLocation, List<? extends TreeNode> roots, |
| boolean fillIcon) { |
| URI fileURI = URI.createFileURI(fileLocation); |
| Resource.Factory resourceFactory = new NodesResourceFactoryImpl(); |
| // resourceFactory cannot be null |
| Resource res = resourceFactory.createResource(fileURI); |
| fillTree(res, roots, fillIcon); |
| try { |
| res.save(Collections.EMPTY_MAP); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| |
| } |
| |
| /** |
| * Translates each {@link TreeNode} into a {@link Node}. |
| * <p> |
| * The label of each {@link TreeNode} displayed in the viewer is set as label of the node |
| * </p> |
| * |
| * @param n |
| * @param saveIcon |
| * Set to true if the icon name should be serialized in the model |
| * @return |
| */ |
| private Node createNode(TreeNode n, boolean saveIcon) { |
| Node newNode = null; |
| if (viewerFilterPredicate.apply(n)) { |
| if (saveIcon) { |
| newNode = NodesFactory.eINSTANCE.createNodeSingleValueAttribute(); |
| } else { |
| newNode = NodesFactory.eINSTANCE.createNode(); |
| } |
| newNode.setName(itemDelegator.getText(n)); |
| for (TreeNode child : n.getChildren()) { |
| Node createNode = createNode(child, saveIcon); |
| if (createNode != null) { |
| newNode.getContainmentRef1().add(createNode); |
| } |
| } |
| if (saveIcon) { |
| // Save the icon name to test the picture |
| Object icon = itemDelegator.getImage(n); |
| ((NodeSingleValueAttribute)newNode).setSingleValuedAttribute(Joiner.on(',') |
| .join(StereotypedElementItemProviderTestUtil.getIconsLocation(icon))); |
| } |
| } |
| return newNode; |
| } |
| |
| private void fillTree(Resource resource, List<? extends TreeNode> roots, boolean fillIcon) { |
| for (TreeNode n : roots) { |
| Node createNode = createNode(n, fillIcon); |
| if (createNode != null) { |
| resource.getContents().add(createNode); |
| } |
| } |
| } |
| } |
| } |