blob: d5a180ed07023f4e71d403433988f715ebccca0f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2017 EclipseSource Muenchen 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:
* Stefan Dirix - initial API and implementation
* Christian W. Damus - bug 527638
*******************************************************************************/
package org.eclipse.papyrus.compare.diagram.tests.saveparameter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.ide.ui.internal.logical.ComparisonScopeBuilder;
import org.eclipse.emf.compare.ide.ui.logical.SynchronizationModel;
import org.eclipse.emf.compare.ide.ui.tests.workspace.TestProject;
import org.eclipse.emf.compare.ide.utils.StorageTraversal;
import org.eclipse.emf.compare.scope.IComparisonScope;
import org.eclipse.emf.compare.uml2.ide.tests.util.ProfileTestUtil;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.impl.ExtensibleURIConverterImpl;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.papyrus.compare.diagram.ide.ui.internal.DiagramMigrationHook;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.Bundle;
/**
* This class tests the SaveParameterHook integration in EMF Compare by using the EMF Compare comparison
* process to save and compare test models.
*
* @author Stefan Dirix <sdirix@eclipsesource.com>
*/
@SuppressWarnings({"restriction", "nls" })
public class SaveParameterHookIntegrationTest {
/**
* The bundle which contains this test.
*/
private static final String TEST_BUNDLE = "org.eclipse.papyrus.compare.diagram.tests";
/**
* The path within this bundle to reach the data for this test.
*/
private static final String BASE_PATH = "src/org/eclipse/papyrus/compare/diagram/tests/saveparameter/data/";
/**
* The name of the temporary project created to test the saving behavior of EMF Compare.
*/
private static final String TEST_PROJECT_NAME = "SaveParameterTestProject";
/**
* The temporary project containing the original and modified files.
*/
private TestProject project;
/**
* Tests if EMF Compare introduces binary changes when saving model files after the comparing process.
*
* @throws Exception
* If the files can not be copied or compared.
*/
@Test
public void testSaveParametersIntegrationA1() throws Exception {
final String localContainer = "a1/";
final List<String> fileNames = Arrays.asList(new String[] {"model.uml", "model.notation" });
assertNoChangeViaSave(localContainer, fileNames);
}
/**
* Tests if EMF Compare introduces binary changes when saving model files after the comparing process.
*
* @throws Exception
* If the files can not be copied or compared.
*/
@Test
public void testSaveParametersIntegrationA2() throws Exception {
final String localContainer = "a2/";
final List<String> fileNames = Arrays
.asList(new String[] {"model.di", "model.uml", "model.notation" });
assertNoChangeViaSave(localContainer, fileNames);
}
/**
* Copies the files specified in {@code fileNames} twice into the temporary project. One set of files is
* then re-saved after the default comparing process of EMF Compare and binary compared to the original
* set of files to determine if EMF Compare introduced any changes.
*
* @param localContainer
* The container containing the files specified in {@code fileNames}. The container is relative
* to {@link #BASE_PATH}.
* @param fileNames
* The files to copy, save and compare which are located in the {@code localContainer}.
* @throws Exception
* * @throws Exception If the files can not be copied or compared.
*/
private void assertNoChangeViaSave(final String localContainer, final Collection<String> fileNames)
throws Exception {
final Bundle bundle = Platform.getBundle(TEST_BUNDLE);
final List<IFile> originalFiles = new ArrayList<IFile>(fileNames.size());
final List<IFile> saveFiles = new ArrayList<IFile>(fileNames.size());
final List<URI> originalResourceURIs = new ArrayList<>(fileNames.size());
final List<String> saveResourceURIStrings = new ArrayList<>(fileNames.size());
final Map<IFile, IFile> originalToSaveMap = new HashMap<>();
// Create originals
for (String fileName : fileNames) {
final String path = BASE_PATH + localContainer + fileName;
final URI fileURI = getFileUri(bundle.getEntry(path));
final IFile originalFile = project.createFile("original/" + fileName, getInputStream(fileURI));
final IFile saveFile = project.getProject().getFile(new Path("save/" + fileName));
originalToSaveMap.put(originalFile, saveFile);
originalFiles.add(originalFile);
originalResourceURIs
.add(URI.createPlatformResourceURI(originalFile.getFullPath().toString(), true));
}
// Run diagram migrations as needed, to avoid those introducing changes
migrateDiagrams(originalResourceURIs);
// Copy the migrated files. Be careful to maintain ordering
project.createFolder("save");
for (IFile originalFile : originalFiles) {
IFile saveFile = originalToSaveMap.get(originalFile);
saveFile.create(originalFile.getContents(true), true, null);
saveFiles.add(saveFile);
saveResourceURIStrings
.add(URI.createPlatformResourceURI(saveFile.getFullPath().toString(), true).toString());
}
// build comparison scope which uses the internal resource sets of EMF Compare
final StorageTraversal traversal = ProfileTestUtil
.createStorageTraversal(saveResourceURIStrings.toArray(new String[0]));
final SynchronizationModel syncModel = new SynchronizationModel(traversal, traversal, null);
final IComparisonScope scope = ComparisonScopeBuilder.create(syncModel, new NullProgressMonitor());
// save all resources touched by EMF Compare
final ResourceSet resourceSet = (ResourceSet)scope.getLeft();
for (Resource resource : resourceSet.getResources()) {
resource.save(null);
}
// check if all files are still identical
for (int i = 0; i < fileNames.size(); i++) {
final IFile originalFile = originalFiles.get(i);
final IFile saveFile = saveFiles.get(i);
compareTextContent(originalFile, saveFile, true);
}
}
/**
* Compares the textual content of both files. The content is only compared after removing all "carriage
* return" characters to allow the test to work properly independent of the given environment.
*
* @param fileA
* One of the files for the comparison.
* @param fileB
* One of the files for the comparison.
* @return {@code true} if both files have the same textual content, {@code false} otherwise.
* @throws IOException
* When there is an error reading one of the files.
*/
private void compareTextContent(IFile fileA, IFile fileB, boolean expectedEqual) throws IOException {
final String textFileA = removeCRCharacters(getText(fileA));
final String textFileB = removeCRCharacters(getText(fileB));
if (expectedEqual) {
assertEquals(textFileB, textFileA);
} else {
assertNotEquals(textFileB, textFileA);
}
}
/**
* Returns a {@link String} with the same content but all "carriage return" characters removed.
*
* @param text
* The {@link String} from which all CR characters shall be removed.
* @return The given {@code text} without CR characters.
*/
private String removeCRCharacters(String text) {
return text.replaceAll("\\r", "");
}
/**
* Reads and returns the content of the given {@link IFile} assuming it is a text file.
*
* @param iFile
* The text file which shall be read.
* @return The content of the given {@link IFile}.
* @throws IOException
* When there is an error reading the file.
*/
private String getText(IFile iFile) throws IOException {
final File file = iFile.getLocation().toFile();
return Files.toString(file, Charsets.UTF_8);
}
/**
* Returns the {@link InputStream} for a given {@link URI}.
*
* @param uri
* The {@link URI} for which the {@link InputStream} is to be determined.
* @return The {@link InputStream} for the given {@link URI}.
* @throws IOException
* If there is a problem obtaining an open input stream.
*/
private InputStream getInputStream(final URI uri) throws IOException {
final URIConverter converter = new ExtensibleURIConverterImpl();
return converter.createInputStream(uri);
}
/**
* Returns the {@link URI} for a given {@link URL}.
*
* @param fileUrl
* The {@link URL} for which the {@link URI} is to be determined.
* @return The {@link URI} for the given {@link URL}.
* @throws IOException
* If an error occurs during the conversion.
*/
private URI getFileUri(final URL fileUrl) throws IOException {
final URL fileLocation = FileLocator.toFileURL(fileUrl);
return URI.createFileURI(fileLocation.getPath());
}
/**
* Initializes the temporary test project.
*
* @throws CoreException
* If an error occurs when (re-)creating the temporary test project.
*/
@Before
public void setupProject() throws CoreException {
project = new TestProject(TEST_PROJECT_NAME);
}
/**
* Disposes the temporary test project.
*
* @throws CoreException
* If an error occurs when disposing the temporary test project.
* @throws IOException
* If an error occurs when disposing the temporary test project.
*/
@After
public void disposeProject() throws CoreException, IOException {
project.dispose();
}
/**
* Migrate the diagrams in a bunch of resources and save them.
*
* @param resourceURIs
* the resources in which to migrate diagrams
*/
void migrateDiagrams(Collection<URI> resourceURIs) {
ResourceSet rset = new ResourceSetImpl();
DiagramMigrationHook hook = new DiagramMigrationHook();
for (URI next : resourceURIs) {
rset.getResource(next, true);
}
hook.postLoadingHook(rset, resourceURIs);
// Save the migrations. Note that the original test resources have the
// redundant XMI types, so preserve those
Map<Object, Object> saveOptions = new HashMap<>();
saveOptions.put(XMLResource.OPTION_SAVE_TYPE_INFORMATION, Boolean.TRUE);
saveOptions.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED, Boolean.TRUE);
for (Resource next : rset.getResources()) {
try {
next.save(saveOptions);
} catch (IOException e) {
e.printStackTrace();
fail("Failed to save migrated diagram(s): " + e.getMessage());
}
}
for (Resource next : rset.getResources()) {
next.unload();
}
rset.getResources().clear();
}
}