/*******************************************************************************
* Copyright (c) 2015 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:
* Philip Langer - initial API and implementation
* Stefan Dirix - handle space in file url
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.tests.logical.resolver;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.LinkedHashSet;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.graph.IGraph;
import org.eclipse.emf.compare.ide.ui.internal.logical.resolver.DefaultResolutionContext;
import org.eclipse.emf.compare.ide.ui.internal.logical.resolver.DependencyGraphUpdater;
import org.eclipse.emf.compare.ide.ui.internal.logical.resolver.IImplicitDependencies;
import org.eclipse.emf.compare.ide.ui.internal.logical.resolver.ModelResourceListener;
import org.eclipse.emf.compare.ide.ui.internal.logical.resolver.ResourceComputationScheduler;
import org.eclipse.emf.compare.ide.ui.internal.logical.resolver.ThreadedModelResolver;
import org.eclipse.emf.compare.ide.ui.logical.SynchronizationModel;
import org.eclipse.emf.compare.ide.ui.tests.CompareTestCase;
import org.eclipse.emf.compare.ide.ui.tests.workspace.TestProject;
import org.eclipse.emf.compare.ide.utils.StorageTraversal;
import org.eclipse.emf.compare.internal.utils.Graph;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.junit.Test;
import org.osgi.framework.Bundle;
/**
* Tests the integration of the modelDependencyProvider extension in the {@link ThreadedModelResolver}.
* <p>
* The integration is tested by having a model set consisting of three files (file1.ecore, file2.ecore, and
* file3.ecore), which are -- for the sake of the test -- always specified as dependency by a dependency
* provider. We run the {@link ThreadedModelResolver} with and without this dependency provider and assert
* that the files aren't or are part of the resulting storage traversal that is resolved.
* </p>
* <p>
* More concretely, file2.ecore has a real dependency to file3.ecore, whereas file1.ecore has no dependency
* neither to file2.ecore nor file3.ecore. Thus, calling the {@link ThreadedModelResolver} with file1.ecore
* would not include file2.ecore and file3.ecore without a custom dependency provider. Therefore, we test the
* integration by adding a dependency provider which always adds file1.ecore and file2.ecore to the
* dependencies. As a result, calling the {@link ThreadedModelResolver} with the custom dependency provider
* with each of the files, file1.ecore, file2.ecore, or file3.ecore should always result into a storage
* traversal of all three files.
* </p>
*
* @author Philip Langer <planger@eclipsesource.com>
*/
@SuppressWarnings({"nls" })
public class ThreadedModelResolverWithCustomDependencyProviderTest extends CompareTestCase {
private static final String TEST_BUNDLE = "org.eclipse.emf.compare.ide.ui.tests";
private static final String TEST_DATA_PATH = "src/org/eclipse/emf/compare/ide/ui/tests/logical/resolver/data/case1/";
private static final String MODEL_FILE1 = "file1.ecore";
private static final String MODEL_FILE2 = "file2.ecore";
private static final String MODEL_FILE3 = "file3.ecore";
private IProgressMonitor monitor = new NullProgressMonitor();
@Test
public void testResolveLocalModelFromFile1WithoutDependencyProvider()
throws IOException, CoreException, URISyntaxException, InterruptedException {
final ModelSet modelSet = createProjectWithModelSet();
final ThreadedModelResolver resolver = createModelResolver();
final StorageTraversal traversal = resolver.resolveLocalModel(modelSet.file1, monitor);
assertEquals(1, traversal.getStorages().size());
assertContainsFile(traversal, modelSet.file1);
}
@Test
public void testResolveLocalModelFromFile2WithoutDependencyProvider()
throws IOException, CoreException, URISyntaxException, InterruptedException {
final ModelSet modelSet = createProjectWithModelSet();
final ThreadedModelResolver resolver = createModelResolver();
final StorageTraversal traversal = resolver.resolveLocalModel(modelSet.file2, monitor);
assertEquals(2, traversal.getStorages().size());
assertContainsFile(traversal, modelSet.file2);
assertContainsFile(traversal, modelSet.file3);
}
@Test
public void testResolveLocalModelFromFile1WithDependencyProvider()
throws IOException, CoreException, URISyntaxException, InterruptedException {
final ModelSet modelSet = createProjectWithModelSet();
final ThreadedModelResolver resolver = createModelResolverWithCustomImplicitDependencies();
final StorageTraversal traversal = resolver.resolveLocalModel(modelSet.file1, monitor);
assertContainsAllFiles(traversal, modelSet);
}
@Test
public void testResolveLocalModelFromFile2WithDependencyProvider()
throws IOException, CoreException, URISyntaxException, InterruptedException {
final ModelSet modelSet = createProjectWithModelSet();
final ThreadedModelResolver resolver = createModelResolverWithCustomImplicitDependencies();
final StorageTraversal traversal = resolver.resolveLocalModel(modelSet.file2, monitor);
assertContainsAllFiles(traversal, modelSet);
}
@Test
public void testResolveLocalModelsTwoWayFromFile1WithoutDependencyProvider()
throws IOException, CoreException, URISyntaxException, InterruptedException {
final ModelSet leftModelSet = createProjectWithModelSet("Left");
final ModelSet rightModelSet = createProjectWithModelSet("Right");
final ThreadedModelResolver resolver = createModelResolver();
final SynchronizationModel synchronizationModel = resolver.resolveLocalModels(leftModelSet.file1,
rightModelSet.file1, null, monitor);
assertEquals(1, synchronizationModel.getLeftTraversal().getStorages().size());
assertContainsFile(synchronizationModel.getLeftTraversal(), leftModelSet.file1);
assertEquals(1, synchronizationModel.getRightTraversal().getStorages().size());
assertContainsFile(synchronizationModel.getRightTraversal(), rightModelSet.file1);
assertTrue(synchronizationModel.getOriginTraversal().getStorages().isEmpty());
}
@Test
public void testResolveLocalModelsThreeWayFromFile1WithoutDependencyProvider()
throws IOException, CoreException, URISyntaxException, InterruptedException {
final ModelSet leftModelSet = createProjectWithModelSet("Left");
final ModelSet rightModelSet = createProjectWithModelSet("Right");
final ModelSet originModelSet = createProjectWithModelSet("Origin");
final ThreadedModelResolver resolver = createModelResolver();
final SynchronizationModel synchronizationModel = resolver.resolveLocalModels(leftModelSet.file1,
rightModelSet.file1, originModelSet.file1, monitor);
assertEquals(1, synchronizationModel.getLeftTraversal().getStorages().size());
assertContainsFile(synchronizationModel.getLeftTraversal(), leftModelSet.file1);
assertEquals(1, synchronizationModel.getRightTraversal().getStorages().size());
assertContainsFile(synchronizationModel.getRightTraversal(), rightModelSet.file1);
assertEquals(1, synchronizationModel.getOriginTraversal().getStorages().size());
assertContainsFile(synchronizationModel.getOriginTraversal(), originModelSet.file1);
}
@Test
public void testResolveLocalModelsTwoWayFromFile1WithDependencyProvider()
throws IOException, CoreException, URISyntaxException, InterruptedException {
final ModelSet leftModelSet = createProjectWithModelSet("Left");
final ModelSet rightModelSet = createProjectWithModelSet("Right");
final ThreadedModelResolver resolver = createModelResolverWithCustomImplicitDependencies();
final SynchronizationModel synchronizationModel = resolver.resolveLocalModels(leftModelSet.file1,
rightModelSet.file1, null, monitor);
assertContainsAllFiles(synchronizationModel.getLeftTraversal(), leftModelSet);
assertContainsAllFiles(synchronizationModel.getRightTraversal(), rightModelSet);
assertTrue(synchronizationModel.getOriginTraversal().getStorages().isEmpty());
}
@Test
public void testResolveLocalModelsThreeWayFromFile1WithDependencyProvider()
throws IOException, CoreException, URISyntaxException, InterruptedException {
final ModelSet leftModelSet = createProjectWithModelSet("Left");
final ModelSet rightModelSet = createProjectWithModelSet("Right");
final ModelSet originModelSet = createProjectWithModelSet("Origin");
final ThreadedModelResolver resolver = createModelResolverWithCustomImplicitDependencies();
final SynchronizationModel synchronizationModel = resolver.resolveLocalModels(leftModelSet.file1,
rightModelSet.file1, originModelSet.file1, monitor);
assertContainsAllFiles(synchronizationModel.getLeftTraversal(), leftModelSet);
assertContainsAllFiles(synchronizationModel.getRightTraversal(), rightModelSet);
assertContainsAllFiles(synchronizationModel.getOriginTraversal(), originModelSet);
}
private void assertContainsAllFiles(StorageTraversal traversal, ModelSet modelSet) {
assertEquals(3, traversal.getStorages().size());
assertContainsFile(traversal, modelSet.file1);
assertContainsFile(traversal, modelSet.file3);
assertContainsFile(traversal, modelSet.file2);
}
private void assertContainsFile(StorageTraversal traversal, final IFile iFile) {
assertTrue(Iterables.any(traversal.getStorages(), containsFile(iFile)));
}
private static Predicate<IStorage> containsFile(final IFile iFile) {
return new Predicate<IStorage>() {
public boolean apply(IStorage input) {
return iFile.getFullPath().equals(input.getFullPath());
}
};
}
private ThreadedModelResolver createModelResolver() {
ThreadedModelResolver resolver = new ThreadedModelResolver();
resolver.setGraph(new Graph<URI>());
resolver.initialize();
return resolver;
}
private ThreadedModelResolver createModelResolverWithCustomImplicitDependencies() {
ThreadedModelResolver resolver = new ThreadedModelResolver() {
@Override
protected DefaultResolutionContext createContext(EventBus eventBus, IGraph<URI> graph) {
return new DefaultResolutionContext(eventBus, graph,
new DependencyGraphUpdater<URI>(graph, eventBus),
new ResourceComputationScheduler<URI>(), new ModelResourceListener()) {
@Override
public synchronized IImplicitDependencies getImplicitDependencies() {
return new IImplicitDependencies() {
public Set<URI> of(URI uri, URIConverter uriConverter) {
final String uriString = uri.toPlatformString(false);
final String baseUriString = uriString.substring(0,
uriString.lastIndexOf("/"));
final String file1UriString = baseUriString + "/" + MODEL_FILE1;
final String file2UriString = baseUriString + "/" + MODEL_FILE2;
final URI file1Uri = URI.createPlatformResourceURI(file1UriString, false);
final URI file2Uri = URI.createPlatformResourceURI(file2UriString, false);
final LinkedHashSet<URI> dependencies = Sets.newLinkedHashSet();
dependencies.add(uri);
dependencies.add(file1Uri);
dependencies.add(file2Uri);
return dependencies;
}
};
}
};
}
};
resolver.setGraph(new Graph<URI>());
resolver.initialize();
return resolver;
}
private ModelSet createProjectWithModelSet() throws CoreException, IOException, URISyntaxException {
return createProjectWithModelSet("Project");
}
private ModelSet createProjectWithModelSet(String name)
throws CoreException, IOException, URISyntaxException {
final IProject iProject = new TestProject(name).getProject();
final File file1 = project.getOrCreateFile(iProject, MODEL_FILE1);
final File file2 = project.getOrCreateFile(iProject, MODEL_FILE2);
final File file3 = project.getOrCreateFile(iProject, MODEL_FILE3);
final Bundle bundle = Platform.getBundle(TEST_BUNDLE);
final URI file1Uri = getFileUri(bundle.getEntry(TEST_DATA_PATH + MODEL_FILE1));
final URI file2Uri = getFileUri(bundle.getEntry(TEST_DATA_PATH + MODEL_FILE2));
final URI file3Uri = getFileUri(bundle.getEntry(TEST_DATA_PATH + MODEL_FILE3));
copyFile(toFile(file1Uri), file1);
copyFile(toFile(file2Uri), file2);
copyFile(toFile(file3Uri), file3);
final IFile iFile1 = project.getIFile(iProject, file1);
final IFile iFile2 = project.getIFile(iProject, file2);
final IFile iFile3 = project.getIFile(iProject, file3);
return new ModelSet(iFile1, iFile2, iFile3);
}
private URI getFileUri(final URL bundleUrl) throws IOException {
URL fileLocation = FileLocator.toFileURL(bundleUrl);
return URI.createFileURI(fileLocation.getPath());
}
private File toFile(final URI fileUri) throws URISyntaxException {
return new File(fileUri.toFileString());
}
private class ModelSet {
protected IFile file1;
protected IFile file2;
protected IFile file3;
public ModelSet(IFile file1, IFile file2, IFile file3) {
this.file1 = file1;
this.file2 = file2;
this.file3 = file3;
}
}
}