/******************************************************************************* | |
* Copyright (c) 2008-2011 Chair for Applied Software Engineering, | |
* Technische Universitaet Muenchen. | |
* 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: | |
* wesendon | |
******************************************************************************/ | |
package org.eclipse.emf.emfstore.client.conflictdetection.test.merging; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertTrue; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashSet; | |
import java.util.LinkedHashSet; | |
import java.util.List; | |
import java.util.Set; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.emfstore.client.test.common.cases.ESTest; | |
import org.eclipse.emf.emfstore.internal.client.model.ProjectSpace; | |
import org.eclipse.emf.emfstore.internal.client.model.changeTracking.merging.DecisionManager; | |
import org.eclipse.emf.emfstore.internal.client.model.changeTracking.merging.conflict.VisualConflict; | |
import org.eclipse.emf.emfstore.internal.client.model.util.EMFStoreCommand; | |
import org.eclipse.emf.emfstore.internal.common.model.ModelElementId; | |
import org.eclipse.emf.emfstore.internal.common.model.Project; | |
import org.eclipse.emf.emfstore.internal.server.conflictDetection.ChangeConflictSet; | |
import org.eclipse.emf.emfstore.internal.server.conflictDetection.ConflictDetector; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.ChangePackage; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.AbstractOperation; | |
/** | |
* Helper super class for merge tests. | |
* | |
* @author wesendon | |
*/ | |
public class MergeTest extends ESTest { | |
private MergeCase mergeCase; | |
/** | |
* Default Constructor. | |
* | |
* @return case helper | |
*/ | |
public MergeCase newMergeCase() { | |
return newMergeCase(new EObject[0]); | |
} | |
public MergeCase newMergeCase(EObject... objs) { | |
mergeCase = new MergeCase(); | |
mergeCase.add(objs); | |
mergeCase.ensureCopy(); | |
return mergeCase; | |
} | |
public List<ModelElementId> getIds(EObject... objs) { | |
final ArrayList<ModelElementId> result = new ArrayList<ModelElementId>(); | |
for (final EObject obj : objs) { | |
result.add(mergeCase.getMyId(obj)); | |
} | |
return result; | |
} | |
public ModelElementId getId(EObject obj) { | |
return mergeCase.getMyId(obj); | |
} | |
public ModelElementId getMyId(EObject obj) { | |
return mergeCase.getMyId(obj); | |
} | |
public ModelElementId getTheirId(EObject obj) { | |
return mergeCase.getTheirId(obj); | |
} | |
/** | |
* Helper class for merge tests. It manages the two projectspaces and offers covenience methods. | |
* | |
* @author wesendon | |
*/ | |
public class MergeCase { | |
private ProjectSpace theirProjectSpace; | |
private void add(final EObject... objs) { | |
new EMFStoreCommand() { | |
@Override | |
protected void doRun() { | |
for (final EObject obj : objs) { | |
getProject().addModelElement(obj); | |
} | |
} | |
}.run(false); | |
} | |
public void addTheirs(final EObject... objs) { | |
new EMFStoreCommand() { | |
@Override | |
protected void doRun() { | |
for (final EObject obj : objs) { | |
getTheirProject().addModelElement(obj); | |
} | |
} | |
}.run(false); | |
} | |
@SuppressWarnings("unchecked") | |
public <T extends EObject> T getMyItem(T id) { | |
ensureCopy(); | |
return (T) getProject().getModelElement(byId(id)); | |
} | |
public ModelElementId getMyId(EObject obj) { | |
return getProject().getModelElementId(obj); | |
} | |
public ModelElementId getTheirId(EObject obj) { | |
return getTheirProject().getModelElementId(getTheirItem(obj)); | |
} | |
@SuppressWarnings("unchecked") | |
public <T extends EObject> T getTheirItem(T id) { | |
ensureCopy(); | |
return (T) getTheirProject().getModelElement(byId(id)); | |
} | |
private ModelElementId byId(EObject id) { | |
return getProject().getModelElementId(id); | |
} | |
public void ensureCopy() { | |
if (theirProjectSpace == null) { | |
new EMFStoreCommand() { | |
@Override | |
protected void doRun() { | |
clearOperations(); | |
theirProjectSpace = cloneProjectSpace(getProjectSpace()); | |
} | |
}.run(false); | |
} | |
} | |
public Project getTheirProject() { | |
ensureCopy(); | |
return theirProjectSpace.getProject(); | |
} | |
public ProjectSpace getTheirProjectSpace() { | |
ensureCopy(); | |
return theirProjectSpace; | |
} | |
public DecisionManager execute() { | |
ensureCopy(); | |
final List<ChangePackage> myChangePackages = Arrays.asList(getProjectSpace().getLocalChangePackage(true)); | |
final List<ChangePackage> theirChangePackages = Arrays.asList(getTheirProjectSpace().getLocalChangePackage( | |
true)); | |
final ChangeConflictSet changeConflictSet = new ConflictDetector().calculateConflicts(myChangePackages, | |
theirChangePackages, getProject()); | |
final DecisionManager manager = new DecisionManager(getProject(), changeConflictSet, false); | |
return manager; | |
} | |
public <T extends VisualConflict> MergeTestQuery hasConflict(Class<T> clazz, int expectedConflicts) { | |
final MergeTestQuery query = new MergeTestQuery(execute()); | |
return query.hasConflict(clazz, expectedConflicts); | |
} | |
public <T extends VisualConflict> MergeTestQuery hasConflict(Class<T> clazz) { | |
if (clazz == null) { | |
final ArrayList<VisualConflict> conflicts = execute().getConflicts(); | |
assertEquals(0, conflicts.size()); | |
return null; | |
} | |
return hasConflict(clazz, 1); | |
} | |
public ProjectSpace getMyProjectSpace() { | |
return getProjectSpace(); | |
} | |
} | |
public class MergeTestQuery { | |
private final DecisionManager manager; | |
private ArrayList<VisualConflict> conflicts; | |
private Object lastObject; | |
private final HashSet<AbstractOperation> mySeen; | |
private final HashSet<AbstractOperation> theirSeen; | |
public MergeTestQuery(DecisionManager manager) { | |
this.manager = manager; | |
mySeen = new LinkedHashSet<AbstractOperation>(); | |
theirSeen = new LinkedHashSet<AbstractOperation>(); | |
} | |
public <T extends VisualConflict> MergeTestQuery hasConflict(Class<T> clazz, int i) { | |
conflicts = manager.getConflicts(); | |
assertEquals("Number of conflicts", i, conflicts.size()); //$NON-NLS-1$ | |
final VisualConflict currentConflict = currentConflict(); | |
if (!clazz.isInstance(currentConflict)) { | |
throw new AssertionError("Expected: " + clazz.getName() + " but found: " //$NON-NLS-1$ //$NON-NLS-2$ | |
+ (currentConflict == null ? "null" : currentConflict.getClass().getName())); //$NON-NLS-1$ | |
} | |
return this; | |
} | |
private VisualConflict currentConflict() { | |
return conflicts.get(0); | |
} | |
@SuppressWarnings("unchecked") | |
public <T extends AbstractOperation> T getMy(Class<T> class1) { | |
final AbstractOperation myOp = currentConflict().getMyOperation(); | |
if (!class1.isInstance(myOp)) { | |
throw new AssertionError("Expected: " + class1.getName() + " but found: " //$NON-NLS-1$ //$NON-NLS-2$ | |
+ (myOp == null ? "null" : myOp.getClass().getName())); //$NON-NLS-1$ | |
} | |
return (T) myOp; | |
} | |
@SuppressWarnings("unchecked") | |
public <T extends AbstractOperation> T getTheir(Class<T> class1) { | |
final AbstractOperation theirOp = currentConflict().getTheirOperation(); | |
assertTrue(class1.isInstance(theirOp)); | |
return (T) theirOp; | |
} | |
public <T extends AbstractOperation> MergeTestQuery myIs(Class<T> class1) { | |
last(true, getMy(class1)); | |
return this; | |
} | |
public <T extends AbstractOperation> MergeTestQuery myOtherContains(Class<T> class1) { | |
final Set<AbstractOperation> ops = currentConflict().getMyOperations(); | |
for (final AbstractOperation op : ops) { | |
if (class1.isInstance(op) && op != currentConflict().getMyOperation()) { | |
last(true, op); | |
return this; | |
} | |
} | |
throw new AssertionError("Expected: " + class1.getName() + " in other my operations but was not found"); //$NON-NLS-1$ //$NON-NLS-2$ | |
} | |
public <T extends AbstractOperation> MergeTestQuery theirsIs(Class<T> class1) { | |
last(false, getTheir(class1)); | |
return this; | |
} | |
private void last(boolean my, AbstractOperation op) { | |
lastObject = op; | |
if (my) { | |
mySeen.add(op); | |
} else { | |
theirSeen.add(op); | |
} | |
} | |
public MergeTestQuery andNoOtherMyOps() { | |
final HashSet<AbstractOperation> my = new LinkedHashSet<AbstractOperation>(currentConflict() | |
.getMyOperations()); | |
my.removeAll(mySeen); | |
assertEquals(0, my.size()); | |
return this; | |
} | |
public MergeTestQuery andNoOtherTheirOps() { | |
final HashSet<AbstractOperation> theirs = new LinkedHashSet<AbstractOperation>(currentConflict() | |
.getTheirOperations()); | |
theirs.removeAll(theirSeen); | |
assertEquals(0, theirs.size()); | |
return this; | |
} | |
public MergeTestQuery andReturns(String methodName, Object b) { | |
assertTrue(lastObject != null); | |
try { | |
for (final Method method : lastObject.getClass().getMethods()) { | |
if (method.getName().equals(methodName)) { | |
final Object invoke = method.invoke(lastObject, (Object[]) null); | |
assertEquals(b, invoke); | |
return this; | |
} | |
} | |
} catch (final IllegalArgumentException e) { | |
} catch (final IllegalAccessException e) { | |
} catch (final InvocationTargetException e) { | |
} | |
throw new AssertionError("No such method"); //$NON-NLS-1$ | |
} | |
} | |
} |