/*******************************************************************************
* Copyright (c) 2015 EclipseSource Munich 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:
* Florian Zoubek - initial API and implementation
* Philip Langer - refactoring and minor improvements
*******************************************************************************/
package org.eclipse.emf.compare.ide.ui.tests.unit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.compare.ide.ui.dependency.DependencyProviderDescriptor;
import org.eclipse.emf.compare.ide.ui.dependency.IDependencyProvider;
import org.eclipse.emf.compare.ide.ui.dependency.ModelDependencyProviderRegistry;
import org.eclipse.emf.compare.ide.ui.internal.EMFCompareIDEUIPlugin;
import org.eclipse.emf.compare.ide.ui.tests.egit.CompareGitTestCase;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.InternalEObject;
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.ResourceSetImpl;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.lib.Constants;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@SuppressWarnings({"nls", "restriction" })
public class MovedImplicitResourceAmongChangedResourcesTest extends CompareGitTestCase {
private static final HashMap<Object, Object> EMPTY_MAP = new HashMap<Object, Object>();
private static final String MASTER = Constants.R_HEADS + Constants.MASTER;
private static final String MOVED_MODEL_BRANCH = Constants.R_HEADS + "movedModelBranch";
private static final String CHANGED_MODEL_BRANCH = Constants.R_HEADS + "changedModelBranch";
private static final String ROOT_FILE_PATH = "directory1/file1.ecore";
private static final String IMPLICIT_FILE_PATH = "directory1/file2.ecore";
private static final String IMPLICIT_FILE_MOVED_PATH = "directory2/file2.ecore";
private static final String SUBMODEL_FILE_PATH = "directory1/file3.ecore";
private static final String SUBMODEL_FILE_MOVED_PATH = "directory2/file3.ecore";
private File rootFile;
private File identicalFile;
private File submodelFile;
private IFile rootIFile;
private IFile identicalIFile;
private IFile submodelIFile;
private ResourceSet resourceSet;
private IProject iProject;
private Resource rootResource;
private Resource identicalResource;
private Resource submodelResource;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
iProject = project.getProject();
resourceSet = new ResourceSetImpl();
rootFile = project.getOrCreateFile(iProject, ROOT_FILE_PATH);
identicalFile = project.getOrCreateFile(iProject, IMPLICIT_FILE_PATH);
submodelFile = project.getOrCreateFile(iProject, SUBMODEL_FILE_PATH);
rootIFile = project.getIFile(iProject, rootFile);
identicalIFile = project.getIFile(iProject, identicalFile);
submodelIFile = project.getIFile(iProject, submodelFile);
rootResource = connectResource(rootIFile, resourceSet);
identicalResource = connectResource(identicalIFile, resourceSet);
submodelResource = connectResource(submodelIFile, resourceSet);
}
@Ignore("Due to Bug 464379, this test no longer works. It needs management of resource renaming via ResourceAttachmentChange.MOVE")
@Test
public void testRebaseNoConflictMovedSubmodel() throws Exception {
setUpMovedIdenticalResourceAndChangedResourceBranches();
installMockModelDependencyProvider(
ImmutableMap.of(submodelFile.getName(), ImmutableSet.of(identicalFile.getName())));
repository.checkoutBranch(MOVED_MODEL_BRANCH);
iProject.refreshLocal(IResource.DEPTH_INFINITE, null);
repository.rebaseLogical(CHANGED_MODEL_BRANCH);
iProject.refreshLocal(IResource.DEPTH_INFINITE, null);
assertTrue(repository.status().getConflicting().isEmpty());
assertFalse(iProject.getFile(IMPLICIT_FILE_PATH).exists());
assertFalse(iProject.getFile(SUBMODEL_FILE_PATH).exists());
final IFile movedSubmodelFile = iProject.getFile(SUBMODEL_FILE_MOVED_PATH);
final IFile movedIdenticalFile = iProject.getFile(IMPLICIT_FILE_MOVED_PATH);
assertTrue(iProject.getFile(ROOT_FILE_PATH).exists());
assertTrue(movedSubmodelFile.exists());
assertTrue(movedIdenticalFile.exists());
// Check the contents
unload(rootResource, identicalResource, submodelResource);
resourceSet.getResources().clear();
rootResource = connectResource(iProject.getFile(ROOT_FILE_PATH), resourceSet);
Resource movedIdenticalResource = connectResource(movedIdenticalFile, resourceSet);
Resource movedSubmodelResource = connectResource(movedSubmodelFile, resourceSet);
rootResource.load(EMPTY_MAP);
movedIdenticalResource.load(EMPTY_MAP);
movedSubmodelResource.load(EMPTY_MAP);
EPackage testRootPack = (EPackage)rootResource.getContents().get(0);
assertEquals("parent1", testRootPack.getName());
EPackage testImplicitRootPack = (EPackage)movedIdenticalResource.getContents().get(0);
assertEquals("parent2", testImplicitRootPack.getName());
EPackage testSubmodelPack = testRootPack.getESubpackages().get(0);
assertEquals("child", testSubmodelPack.getName());
assertSame(movedSubmodelResource, ((InternalEObject)testSubmodelPack).eDirectResource());
EClass testC1 = (EClass)testSubmodelPack.getEClassifiers().get(0);
assertEquals("C1", testC1.getName());
EClass nonConflictingClass = (EClass)testSubmodelPack.getEClassifiers().get(1);
assertEquals("NonConflicting", nonConflictingClass.getName());
}
/**
* Sets up a git repository with a model and a submodel with an implicit dependency in the master branch,
* and two branches that base on the master branch: A branch {@link #MOVED_MODEL_BRANCH} with the submodel
* and implicit dependency moved into another directory, as well as a branch {@link #CHANGED_MODEL_BRANCH}
* with the submodel changed.
*/
public void setUpMovedIdenticalResourceAndChangedResourceBranches() throws Exception {
EPackage root = createPackage(null, "parent1");
EPackage implicitRoot = createPackage(null, "parent2");
EPackage submodelChild = createPackage(root, "child");
createClass(submodelChild, "C1");
saveTestResource(submodelResource, submodelChild);
saveTestResource(identicalResource, implicitRoot);
saveTestResource(rootResource, root);
repository.addAllAndCommit("initial-commit");
// create and checkout branch for the moved submodel
repository.createBranch(MASTER, MOVED_MODEL_BRANCH);
repository.checkoutBranch(MOVED_MODEL_BRANCH);
iProject.refreshLocal(IResource.DEPTH_INFINITE, null);
reload(rootResource, submodelResource, identicalResource);
// create new files with "moved" path
IFile movedSubmodelFile = project.getIFile(iProject,
project.getOrCreateFile(iProject, SUBMODEL_FILE_MOVED_PATH));
IFile movedIdenticalFile = project.getIFile(iProject,
project.getOrCreateFile(iProject, IMPLICIT_FILE_MOVED_PATH));
Resource movedSubRes = connectResource(movedSubmodelFile, resourceSet);
Resource movedIdenticalRes = connectResource(movedIdenticalFile, resourceSet);
// save the existing objects from the old files into the new "moved" files
saveTestResource(movedSubRes, (EPackage)findObject(submodelResource, "child"));
saveTestResource(movedIdenticalRes, (EPackage)findObject(identicalResource, "parent2"));
// save other resources as well
save(rootResource, submodelResource, identicalResource);
// delete old files
iProject.getFile(IMPLICIT_FILE_PATH).delete(true, new NullProgressMonitor());
iProject.getFile(SUBMODEL_FILE_PATH).delete(true, new NullProgressMonitor());
// remove former files from the index
repository.removeFromIndex(submodelIFile);
repository.removeFromIndex(identicalIFile);
repository.addAllAndCommit("Moved submodel file and implicit dependency to other directory");
// create and checkout branch for the model changes
repository.createBranch(MASTER, CHANGED_MODEL_BRANCH);
repository.checkoutBranch(CHANGED_MODEL_BRANCH);
repository.reset(CHANGED_MODEL_BRANCH, ResetType.HARD);
iProject.refreshLocal(IResource.DEPTH_INFINITE, null);
// reload resources
unload(rootResource, identicalResource, submodelResource, movedIdenticalRes, movedSubRes);
resourceSet.getResources().clear();
reload(rootResource, identicalResource, submodelResource);
// add a class and save all resources
createClass((EPackage)submodelResource.getContents().get(0), "NonConflicting");
save(submodelResource);
save(identicalResource);
save(rootResource);
repository.addAllAndCommit("Added class to child.");
// reset current branch to master
repository.checkoutBranch(MASTER);
repository.reset(MASTER, ResetType.HARD);
iProject.refreshLocal(IResource.DEPTH_INFINITE, null);
// unload resources
unload(rootResource, identicalResource, submodelResource, movedIdenticalRes, movedSubRes);
resourceSet.getResources().clear();
}
protected void saveTestResource(Resource resource, EPackage pkg) throws IOException, CoreException {
resource.getContents().clear();
resource.getContents().add(pkg);
save(resource);
}
@Override
@After
public void tearDown() throws Exception {
getModelDependencyProviderRegistry().clear();
unload(rootResource, identicalResource, submodelResource);
super.tearDown();
}
private ModelDependencyProviderRegistry getModelDependencyProviderRegistry() {
return EMFCompareIDEUIPlugin.getDefault().getModelDependencyProviderRegistry();
}
private void installMockModelDependencyProvider(
final ImmutableMap<String, ImmutableSet<String>> dependencies) {
getModelDependencyProviderRegistry().addProvider("mock",
new DependencyProviderDescriptor(null, null) {
private final IDependencyProvider mock = new MockDependencyProvider(dependencies);
@Override
public IDependencyProvider getDependencyProvider() {
return mock;
}
});
}
private class MockDependencyProvider implements IDependencyProvider {
private ImmutableMap<String, ImmutableSet<String>> dependencies;
public MockDependencyProvider(ImmutableMap<String, ImmutableSet<String>> dependencies) {
this.dependencies = dependencies;
}
public boolean apply(URI uri) {
return dependencies.containsKey(uri.lastSegment());
}
public Set<URI> getDependencies(URI uri, URIConverter uriConverter) {
if (dependencies.containsKey(uri.lastSegment())) {
final Set<URI> uris = new HashSet<URI>();
for (String fileName : dependencies.get(uri.lastSegment())) {
final URI dependentUri = uri.trimSegments(1).appendSegment(fileName);
if (uriConverter.exists(dependentUri, Collections.emptyMap())) {
uris.add(dependentUri);
}
}
return uris;
} else {
return Collections.emptySet();
}
}
}
}