blob: c27e0dc9e12b3ef63d38dd8ba8e1b9990235470f [file] [log] [blame]
/*******************************************************************************
* 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 java.util.Arrays.asList;
import java.util.Arrays;
import org.eclipse.emf.emfstore.client.test.common.dsl.Create;
import org.eclipse.emf.emfstore.internal.client.model.changeTracking.merging.conflict.conflicts.MultiAttributeConflict;
import org.eclipse.emf.emfstore.internal.client.model.changeTracking.merging.conflict.conflicts.MultiAttributeSetConflict;
import org.eclipse.emf.emfstore.internal.client.model.changeTracking.merging.conflict.conflicts.MultiAttributeSetSetConflict;
import org.eclipse.emf.emfstore.internal.client.model.util.EMFStoreCommand;
import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.MultiAttributeOperation;
import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.MultiAttributeSetOperation;
import org.eclipse.emf.emfstore.test.model.TestElement;
import org.junit.Test;
/**
* Merge testcases for {@link MultiAttributeOperation} and {@link MultiAttributeSetOperation}.
*
* @author wesendon
*/
public class MultiAttributeMergeTest extends MergeTest {
private static final String Y2 = "Y"; //$NON-NLS-1$
private static final String GET_REFERENCED_VALUES = "getReferencedValues"; //$NON-NLS-1$
private static final String GET_NEW_VALUE = "getNewValue"; //$NON-NLS-1$
private static final String GET_INDEX = "getIndex"; //$NON-NLS-1$
private static final String Y = "y"; //$NON-NLS-1$
private static final String X2 = "x"; //$NON-NLS-1$
private static final String IS_ADD = "isAdd"; //$NON-NLS-1$
private static final String X = "X"; //$NON-NLS-1$
private static final String C = "c"; //$NON-NLS-1$
private static final String B = "b"; //$NON-NLS-1$
private static final String A = "a"; //$NON-NLS-1$
@Test
public void addFirstVsRemove() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().add(1, X);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().remove(1);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeConflict.class)
// My
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, true)
// Theirs
.theirsIs(MultiAttributeOperation.class).andReturns(IS_ADD, false);
}
@Test
public void addVsRemove() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().add(X);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().remove(1);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeConflict.class)
// My
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, true)
// Theirs
.theirsIs(MultiAttributeOperation.class).andReturns(IS_ADD, false);
}
@Test
public void addManyVsRemove() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().addAll(1, Arrays.asList(X2, Y));
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().remove(1);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeConflict.class)
// My
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, true)
// Theirs
.theirsIs(MultiAttributeOperation.class).andReturns(IS_ADD, false);
}
@Test
public void addManyVsRemoveMany() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().addAll(1, Arrays.asList(X2, Y));
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().removeAll(Arrays.asList(B, C));
}
}.run(false);
mergeCase.hasConflict(MultiAttributeConflict.class)
// My
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, true)
// Theirs
.theirsIs(MultiAttributeOperation.class).andReturns(IS_ADD, false);
}
@Test
public void removeVsRemove() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().remove(1);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().remove(2);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeConflict.class)
// My
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, false)
// Theirs
.theirsIs(MultiAttributeOperation.class).andReturns(IS_ADD, false);
}
@Test
public void removeVsRemoveSameNc() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().remove(1);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().remove(1);
}
}.run(false);
// TODO: false positive, fix later
mergeCase.hasConflict(MultiAttributeConflict.class);
}
@Test
public void removeManyVsRemoveMany() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().removeAll(Arrays.asList(A, B));
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().removeAll(Arrays.asList(B, C));
}
}.run(false);
mergeCase.hasConflict(MultiAttributeConflict.class)
// My
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, false)
// Theirs
.theirsIs(MultiAttributeOperation.class).andReturns(IS_ADD, false);
}
/**
* Remove and Set on the same element.
*/
@Test
public void removeVsSet() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().remove(1);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().set(1, X);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeSetConflict.class)
// My
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, false)
// Theirs
.theirsIs(MultiAttributeSetOperation.class).andReturns(GET_INDEX, 1).andReturns(GET_NEW_VALUE, X);
}
/**
* Remove on a lower remove index than Set.
*/
@Test
public void removeVsSetLowerIndex() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().remove(0);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().set(1, X);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeSetConflict.class)
// My
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, false)
// Theirs
.theirsIs(MultiAttributeSetOperation.class).andReturns(GET_INDEX, 1).andReturns(GET_NEW_VALUE, X);
}
/**
* Remove on a higher remove index than Set. That's a conflict.
*/
@Test
public void removeVsSetHigherIndexNC() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().remove(1);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().set(0, X);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeSetConflict.class);
}
/**
* Remove multiple elements individually vs. Set. Individually removing causes multiple remove operations.
*/
@Test
public void multipleRemoveVsSet() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().remove(1);
mergeCase.getMyItem(element).getStrings().remove(1);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().set(1, X);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeSetConflict.class)
// My first
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, false)
// My Second
.myOtherContains(MultiAttributeOperation.class).andReturns(IS_ADD, false).andNoOtherMyOps()
// Their
.theirsIs(MultiAttributeSetOperation.class).andReturns(GET_INDEX, 1).andReturns(GET_NEW_VALUE, X)
.andNoOtherTheirOps();
}
/**
* Remove multiple elements in one operation vs Set.
*/
@Test
public void multiRemoveVsSet() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().removeAll(asList(B, C));
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().set(1, X);
}
}.run(false);
mergeCase
.hasConflict(MultiAttributeSetConflict.class)
// My first
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, false)
.andReturns(GET_REFERENCED_VALUES, asList(B, C)).andNoOtherMyOps()
// Their
.theirsIs(MultiAttributeSetOperation.class).andReturns(GET_INDEX, 1).andReturns(GET_NEW_VALUE, X)
.andNoOtherTheirOps();
}
/**
* Remove multiple elements in one operation vs Set, with a lower remove index.
*/
@Test
public void multiRemoveVsSetLowerIndex() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().removeAll(asList(A, B));
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().set(2, X);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeSetConflict.class)
// My first
.myIs(MultiAttributeOperation.class).andReturns(IS_ADD, false)
.andReturns(GET_REFERENCED_VALUES, asList(A, B)).andNoOtherMyOps()
// Their
.theirsIs(MultiAttributeSetOperation.class).andReturns(GET_NEW_VALUE, X).andNoOtherTheirOps();
}
/**
* Remove multiple elements in one operation vs Set, with a higher remove index. (NC)
*/
@Test
public void multiRemoveVsSetHigherIndexNC() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().removeAll(asList(B, C));
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().set(0, X);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeSetConflict.class);
}
@Test
public void setVsSet() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().set(1, Y2);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().set(1, X);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeSetSetConflict.class)
// My
.myIs(MultiAttributeSetOperation.class).andReturns(GET_NEW_VALUE, Y2)
// Theirs
.theirsIs(MultiAttributeSetOperation.class).andReturns(GET_NEW_VALUE, X);
}
@Test
public void setVsSetNC() {
final TestElement element = Create.testElement();
element.getStrings().add(A);
element.getStrings().add(B);
element.getStrings().add(C);
final MergeCase mergeCase = newMergeCase(element);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getMyItem(element).getStrings().set(1, Y2);
}
}.run(false);
new EMFStoreCommand() {
@Override
protected void doRun() {
mergeCase.getTheirItem(element).getStrings().set(2, X);
}
}.run(false);
mergeCase.hasConflict(MultiAttributeSetSetConflict.class);
}
}