/******************************************************************************* * 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; } } }