| /******************************************************************************* |
| * 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: |
| * Julian Sommerfeldt - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.emf.emfstore.client.recording.test; |
| |
| import static org.hamcrest.CoreMatchers.instanceOf; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.concurrent.Callable; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.emfstore.client.test.common.cases.ComparingESTest; |
| import org.eclipse.emf.emfstore.client.test.common.dsl.Add; |
| import org.eclipse.emf.emfstore.client.test.common.dsl.Create; |
| import org.eclipse.emf.emfstore.client.util.ESVoidCallable; |
| import org.eclipse.emf.emfstore.client.util.RunESCommand; |
| import org.eclipse.emf.emfstore.internal.client.model.CompositeOperationHandle; |
| import org.eclipse.emf.emfstore.internal.client.model.ESWorkspaceProviderImpl; |
| import org.eclipse.emf.emfstore.internal.client.model.changeTracking.commands.EMFStoreBasicCommandStack; |
| import org.eclipse.emf.emfstore.internal.client.model.exceptions.InvalidHandleException; |
| import org.eclipse.emf.emfstore.internal.common.model.Project; |
| import org.eclipse.emf.emfstore.internal.common.model.impl.IdEObjectCollectionImpl; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.ChangePackage; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.VersioningFactory; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.AbstractOperation; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.CompositeOperation; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.CreateDeleteOperation; |
| import org.eclipse.emf.emfstore.test.model.TestElement; |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| /** |
| * Test some OperationRecorder functionalities. |
| * |
| * @author jsommerfeldt |
| * |
| */ |
| public class OperationRecorderTest extends ComparingESTest { |
| |
| private static final String CONNECTION2 = "connection"; //$NON-NLS-1$ |
| private static final String TARGET2 = "target"; //$NON-NLS-1$ |
| |
| /** |
| * Check the force command setting. |
| */ |
| @Test(expected = RuntimeException.class) |
| public void forceCommands() { |
| disableCompareAtEnd(); |
| getProjectSpace().getOperationManager().getRecorderConfig().setForceCommands(true); |
| final TestElement testElement = Create.testElement(); |
| getProject().getModelElements().add(testElement); |
| } |
| |
| /** |
| * Test adding an element with deleted references. |
| */ |
| @Test |
| public void addElementWithDeletedReference() { |
| |
| final Project project = getProject(); |
| |
| final TestElement element1 = Create.testElement(); |
| final TestElement element2 = Create.testElement(); |
| |
| element1.getReferences().add(element2); |
| |
| RunESCommand.run(new Callable<Void>() { |
| |
| public Void call() throws Exception { |
| project.addModelElement(element2); |
| project.deleteModelElement(element2); |
| project.addModelElement(element1); |
| Assert.assertNotNull(((IdEObjectCollectionImpl) project).getDeletedModelElementId(element2)); |
| return null; |
| } |
| }); |
| } |
| |
| @Test |
| public void supportCommandChaining() { |
| |
| // final TestElement source = Create.testElement("source"); |
| final TestElement target = Create.testElement(TARGET2); |
| final TestElement source = Create.testElement(); |
| |
| Add.toProject(getLocalProject(), source); |
| Add.toProject(getLocalProject(), target); |
| |
| final List<EObject> deletables = new ArrayList<EObject>(); |
| deletables.add(source); |
| deletables.add(target); |
| |
| RunESCommand.run(new ESVoidCallable() { |
| @Override |
| public void run() { |
| boolean inCommandChain = false; |
| for (final EObject deletable : deletables) { |
| if (inCommandChain) { |
| assertTrue(getProjectSpace().getOperationManager().isCommandRunning()); |
| } |
| final CompositeOperationHandle handle = getProjectSpace().getOperationManager() |
| .beginCompositeOperation(); |
| getProject().getModelElements().remove(deletable); |
| try { |
| handle.end("Delete source", StringUtils.EMPTY, getProject().getModelElementId(source)); //$NON-NLS-1$ |
| } catch (final InvalidHandleException ex) { |
| fail(ex.getMessage()); |
| } |
| getProjectSpace().getOperationManager().commandCompleted(null, true); |
| inCommandChain = true; |
| } |
| } |
| }); |
| |
| } |
| |
| /** |
| * Test adding an element with deleted references. |
| */ |
| @Test |
| public void rescueElementAndDeleteIt() { |
| |
| if (ESWorkspaceProviderImpl.getInstance().getEditingDomain() |
| .getCommandStack() instanceof EMFStoreBasicCommandStack) { |
| |
| // ExtensionRegistry.INSTANCE.set(ESOperationModifier.ID, new AutoOperationWrapper()); |
| |
| final Project project = getProject(); |
| |
| // final TestElement source = Create.testElement("source"); |
| final TestElement target = Create.testElement(TARGET2); |
| final TestElement connection = Create.testElement(CONNECTION2); |
| final TestElement source = Create.testElement(); |
| |
| source.getContainedElements().add(connection); |
| connection.setContainer(source); |
| target.getReferences().add(connection); |
| |
| RunESCommand.run(new Callable<Void>() { |
| |
| public Void call() throws Exception { |
| project.addModelElement(source); |
| return null; |
| } |
| }); |
| |
| getClonedProjectSpace().getOperationManager().stopChangeRecording(); |
| ChangePackage cp = RunESCommand.runWithResult(new Callable<ChangePackage>() { |
| |
| public ChangePackage call() throws Exception { |
| final ChangePackage cp = VersioningFactory.eINSTANCE.createChangePackage(); |
| cp.getOperations().addAll(forceGetOperations()); |
| cp.apply(getClonedProjectSpace().getProject()); |
| return cp; |
| } |
| }); |
| clearOperations(); |
| getClonedProjectSpace().getOperationManager().stopChangeRecording(); |
| |
| // do not use commands since we only have them on client side |
| // FIXME: if not wrapped in command fails with transactional editing domain, if wrapped in command assert |
| // fails, |
| // see comment above |
| connection.setContainer(null); |
| |
| final List<AbstractOperation> ops = forceGetOperations(); |
| assertEquals(2, ops.size()); |
| assertThat(ops.get(0), instanceOf(CompositeOperation.class)); |
| assertThat(ops.get(1), instanceOf(CreateDeleteOperation.class)); |
| |
| // apply via change package, because change package does not start a command in contrast |
| // to projectSpace#applyOperations |
| cp = VersioningFactory.eINSTANCE.createChangePackage(); |
| cp.getOperations().addAll(ops); |
| cp.apply(getClonedProjectSpace().getProject()); |
| |
| // in case the connection could not be deleted because of a changed ID, we would expect 2 model elements |
| Assert.assertEquals(1, getClonedProjectSpace().getProject().getModelElements().size()); |
| } |
| } |
| } |