| /****************************************************************************** |
| * Copyright (c) 2002, 2006 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| ****************************************************************************/ |
| |
| package org.eclipse.gmf.tests.runtime.diagram.ui; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import junit.framework.TestCase; |
| |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.draw2d.IFigure; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.transaction.RunnableWithResult; |
| import org.eclipse.emf.transaction.util.TransactionUtil; |
| import org.eclipse.gef.ConnectionEditPart; |
| import org.eclipse.gef.Disposable; |
| import org.eclipse.gef.EditPartViewer; |
| import org.eclipse.gef.Request; |
| import org.eclipse.gef.RootEditPart; |
| import org.eclipse.gef.commands.Command; |
| import org.eclipse.gef.commands.CommandStack; |
| import org.eclipse.gef.commands.CompoundCommand; |
| import org.eclipse.gef.requests.ReconnectRequest; |
| import org.eclipse.gmf.runtime.common.core.command.ICommand; |
| import org.eclipse.gmf.runtime.common.core.util.StringStatics; |
| import org.eclipse.gmf.runtime.common.ui.action.IDisposableAction; |
| import org.eclipse.gmf.runtime.common.ui.action.actions.global.GlobalActionManager; |
| import org.eclipse.gmf.runtime.common.ui.action.global.GlobalActionId; |
| import org.eclipse.gmf.runtime.diagram.ui.actions.internal.SelectAllAction; |
| import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart; |
| import org.eclipse.gmf.runtime.diagram.ui.requests.ChangePropertyValueRequest; |
| import org.eclipse.gmf.runtime.diagram.ui.requests.CreateViewRequest; |
| import org.eclipse.gmf.runtime.diagram.ui.requests.RefreshConnectionsRequest; |
| import org.eclipse.gmf.runtime.diagram.ui.requests.RequestConstants; |
| import org.eclipse.gmf.runtime.emf.core.util.PackageUtil; |
| import org.eclipse.gmf.runtime.notation.Diagram; |
| import org.eclipse.gmf.runtime.notation.View; |
| import org.eclipse.gmf.tests.runtime.diagram.ui.util.DiagramState; |
| import org.eclipse.gmf.tests.runtime.diagram.ui.util.IPresentationTestFixture; |
| import org.eclipse.gmf.tests.runtime.diagram.ui.util.ITestActionCallback; |
| import org.eclipse.gmf.tests.runtime.diagram.ui.util.ITestCommandCallback; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IWorkbenchPage; |
| |
| /** |
| * @author choang |
| * |
| * The abstract base class should be used by any tests that we write for the shapes team |
| * It provides a framework for which the tests will run. |
| * |
| * It contains implementation of some ulitiy helper methods also. |
| * |
| * what's left for you to do? |
| * <p>1. Implement the following abstract methods |
| * <p>a. createConnectorViews - which setups up the diagram with the common shapes and connectors that will be used for your tests |
| * <p>b. setDefaultDiagramExt - sets the diagram extension type which will be used for the tests. Based on the ext given |
| * the diagram manager will use that as a hint to determine which DiagramEditor class to use to manuipulate the diagram. |
| * <p>c. public static suite() - to return the Test that will be our Action Menus will run. Note this is not defined as an abstract |
| * method here because it needs to be a static method in your test class. |
| * d. setTestFixtureLogic() - which sets the <code>org.eclipse.gmf.tests.runtime.diagram.ui.util.IPresentataionTestFixtureLogic</code> class |
| * that will be responsible for creating the fixture(i.e test data) for this test. |
| * <p>2. Add your tests methods |
| * You need to name your tests method like test*. The Junit framework will run all the methods that start with test*. For each test |
| * in you class the Junit framework will first run the setup(), then your testName1() method and the tearDown(). |
| * |
| * |
| */ |
| public abstract class AbstractTestBase extends TestCase { |
| |
| protected IPresentationTestFixture testFixture = null; |
| |
| /** Verbose system property. */ |
| public static final String SYSPROP_VERBOSE = "presentation.test.verbose";//$NON-NLS-1$ |
| |
| /** verbose flag. */ |
| private static boolean _verbose = Boolean.getBoolean(SYSPROP_VERBOSE); |
| |
| /** |
| * Constructor for AbstractTestBase. |
| * @param TestName |
| */ |
| public AbstractTestBase(String arg0) { |
| super(arg0); |
| setTestFixture(); |
| } |
| |
| /** |
| * Enable verbose mode. If enabled, {@link junit.framework.Assert#fail(java.lang.String)} |
| * will print the supplied string; otherwise the string is ignored. |
| * |
| * Verbose mode can also be enabled using the {@link #SYSPROP_VERBOSE} system property. |
| * @param enabled boolean flag |
| */ |
| protected final void enableVerbose( boolean enabled ) { |
| _verbose = enabled; |
| } |
| |
| /** Return the verbose mode. */ |
| public final boolean isVerbose() { |
| return _verbose; |
| |
| } |
| |
| /** Calls <code>System.out.println(msg)</code> if in verbose mode. */ |
| public static final void println( Object msg ) { |
| if ( _verbose ) { |
| System.out.println(msg); |
| } |
| } |
| |
| /** Calls <code>System.out.print(msg)</code> if in verbose mode. */ |
| public static final void print( Object msg ) { |
| if ( _verbose ) { |
| System.out.print(msg); |
| } |
| } |
| |
| /** |
| * Method getCommandStack. |
| * @return CommandStack Command stack for the diagram editor |
| */ |
| protected CommandStack getCommandStack() { |
| return getTestFixture().getCommandStack(); |
| } |
| /** |
| * Method setTestFixtureLogic. |
| * |
| * Sets the fixture logic for the tests. A fixture is the set of "data" that the test will run against |
| * Typically many tests will use the same fixture. |
| * |
| */ |
| protected abstract void setTestFixture(); |
| |
| protected IPresentationTestFixture getTestFixture() { |
| return testFixture; |
| } |
| |
| protected IDiagramWorkbenchPart getDiagramWorkbenchPart() { |
| return getTestFixture().getDiagramWorkbenchPart(); |
| } |
| |
| protected IWorkbenchPage getWorkbenchPage() { |
| return getDiagramWorkbenchPart().getSite().getPage(); |
| } |
| |
| protected DiagramEditPart getDiagramEditPart() { |
| return getTestFixture().getDiagramEditPart(); |
| } |
| |
| protected Diagram getDiagram() { |
| return getTestFixture().getDiagram(); |
| } |
| |
| protected void saveDiagram() { |
| if (getDiagramWorkbenchPart() instanceof IEditorPart) { |
| IWorkbenchPage page = getDiagramWorkbenchPart().getSite().getPage(); |
| |
| page.saveEditor((IEditorPart) getDiagramWorkbenchPart(), false); |
| flushEventQueue(); |
| } |
| } |
| |
| protected boolean isDirty() { |
| if (getDiagramWorkbenchPart() instanceof IEditorPart) { |
| return ((IEditorPart) getDiagramWorkbenchPart()).isDirty(); |
| } |
| return false; |
| } |
| |
| protected DiagramState getDiagramState() { |
| |
| try { |
| return (DiagramState) TransactionUtil |
| .getEditingDomain(getDiagram()).runExclusive( |
| new RunnableWithResult.Impl() { |
| |
| public void run() { |
| |
| setResult(new DiagramState(getDiagramEditPart())); |
| |
| } |
| }); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| assertTrue(false); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Description: Will execute the <code>Command</code> and then the <code>ITestCommandCallBack</code>, which |
| * has the logic to verify that the command executed successful. |
| * <p>The command is executed within an UndoInterval and WriteAction model operation. |
| * @throws <AssertFailError> if the command did not run successfully |
| * @author choang |
| */ |
| protected void testCommand( |
| final ICommand command, |
| final ITestCommandCallback callback) { |
| testCommand(new ICommandProxy(command), callback); |
| } |
| |
| /** |
| * Description: Will execute the <code>Command</code> and then the <code>ITestCommandCallBack</code>, which |
| * has the logic to verify that the command executed successful. |
| * <p>The command is executed within an UndoInterval and WriteAction model operation. |
| * @throws <AssertFailError> if the command did not run successfully |
| * @author choang |
| */ |
| protected void testCommand( |
| final Command command, |
| final ITestCommandCallback callback) { |
| |
| assertNotNull(command); |
| |
| // Had to wrap each command in separate model operations |
| // as if we didn't we got some weird behavior in some of the tests |
| // such as the ConnectorTests#testSelfConnections where we get a null pointer |
| // exception. |
| |
| final DiagramState state1 = getDiagramState(); |
| |
| getCommandStack().execute(command); |
| flushEventQueue(); |
| |
| try { |
| TransactionUtil.getEditingDomain(getDiagram()).runExclusive( |
| new Runnable() { |
| public void run() { |
| callback.onCommandExecution(); |
| } |
| }); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| assertTrue(false); |
| } |
| |
| DiagramState state2 = getDiagramState(); |
| |
| // checking if the command stack is in an undoable state first |
| // not that selfConnections and deleteConnections tests are |
| // failing .. if i do a check via command.canUndo() instead of |
| // using getCommandSTack().canUndo() |
| // which suggest that something is out of synch between the command |
| // and the command stack .. need to look into it later. |
| if (getCommandStack().canUndo()) { |
| |
| getCommandStack().undo(); |
| flushEventQueue(); |
| |
| assertTrue(state1.equals(getDiagramState())); |
| |
| getCommandStack().redo(); |
| flushEventQueue(); |
| } |
| |
| assertTrue(state2.equals(getDiagramState())); |
| |
| } |
| |
| /** |
| * Description: Will execute the <code>Action</code> and then the <code>ITestCommandCallBack</code>, which |
| * has the logic to verify that the command executed successful. |
| * This method will test if the action implements the Disposable interface from GEF |
| * If it does it will call the dispose() method on the action. Callers should not |
| * call it themselves |
| * @throws <AssertFailError> if the command did not run successfully |
| * |
| */ |
| protected void testAction(IAction action, ITestActionCallback callback) { |
| flushEventQueue(); |
| assertTrue(action.isEnabled()); |
| action.run(); |
| flushEventQueue(); |
| if (action instanceof Disposable) |
| ((Disposable) action).dispose(); |
| if (callback != null) |
| callback.onRunExecution(); |
| } |
| |
| /** |
| * Description: Will execute the <code>Action</code> and then the <code>ITestCommandCallBack</code>, which |
| * has the logic to verify that the command executed successful. |
| * This method will test if the action implements the IDisposableAction interface from common.ui |
| * If it does it will first set active the diagrameditorpart of the diagram and then call the init() method before running the action. At the end, |
| * it will call the dispose() method on the action. Callers should not |
| * call these two methods themselves themselves |
| * @throws <AssertFailError> if the command did not run successfully |
| * |
| */ |
| protected void testAction(IDisposableAction action, ITestActionCallback callback) { |
| |
| getWorkbenchPage().activate(getDiagramWorkbenchPart()); |
| action.init(); |
| |
| if( action.isEnabled() ) { |
| |
| action.run(); |
| flushEventQueue(); |
| } |
| |
| action.dispose(); |
| if (callback != null) |
| callback.onRunExecution(); |
| } |
| |
| /** |
| * Does the same as <code>testAction</code> but also does an undo and |
| * redo afterwards and compares the diagram state. |
| * |
| * @param action |
| * @param callback |
| */ |
| protected void testActionAndUndoRedo(IDisposableAction action, ITestActionCallback callback) { |
| |
| final DiagramState state1 = getDiagramState(); |
| |
| getWorkbenchPage().activate(getDiagramWorkbenchPart()); |
| action.init(); |
| |
| if( action.isEnabled() ) { |
| |
| action.run(); |
| flushEventQueue(); |
| } |
| |
| action.dispose(); |
| if (callback != null) |
| callback.onRunExecution(); |
| |
| DiagramState state2 = getDiagramState(); |
| assertTrue("testActionAndUndoRedo: Action cannot be undone.", getCommandStack().canUndo()); //$NON-NLS-1$ |
| getCommandStack().undo(); |
| assertTrue("diagram state different after undo of action", state1.equals(getDiagramState())); //$NON-NLS-1$ |
| getCommandStack().redo(); |
| assertTrue("diagram state different after redo of action", state2.equals(getDiagramState())); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Method testProperty. |
| * Generic method for testing a property change in a view. |
| * |
| * @param view IView to set the property value in |
| * @param property String ID of the property to test |
| * @param expectedValue Object that is the value of the property to test |
| */ |
| protected void testProperty( |
| final View view, |
| final String property, |
| final Object expectedValue) { |
| |
| DiagramEditPart diagramEP = getDiagramEditPart(); |
| assertNotNull( "The DiagramEditPart is null", diagramEP ); //$NON-NLS-1$ |
| |
| RootEditPart rootEP = diagramEP.getRoot(); |
| assertNotNull( "The RootEditPart is null", rootEP ); //$NON-NLS-1$ |
| |
| EditPartViewer viewer = rootEP.getViewer(); |
| assertNotNull( "The EditPartViewer is null", viewer ); //$NON-NLS-1$ |
| |
| Map epRegistry = viewer.getEditPartRegistry(); |
| assertNotNull( "The EditPartRegistery is null", epRegistry ); //$NON-NLS-1$ |
| |
| final IGraphicalEditPart ep = (IGraphicalEditPart) epRegistry.get(view); |
| assertNotNull( "Couldn't find the GraphicalEditPart in the Registery", ep ); //$NON-NLS-1$ |
| |
| Request request = new ChangePropertyValueRequest( |
| StringStatics.BLANK, |
| property, |
| expectedValue ); |
| |
| Command cmd = ep.getCommand( request ); |
| |
| testCommand(cmd, new ITestCommandCallback() { |
| public void onCommandExecution() { |
| assertEquals( expectedValue, ep.getStructuralFeatureValue((EStructuralFeature)PackageUtil.getElement(property)) ); |
| } |
| }); |
| } |
| |
| /** |
| * @see TestCase#setUp() |
| */ |
| protected void setUp() throws Exception { |
| super.setUp(); |
| getTestFixture().setup(); |
| } |
| |
| /** |
| * Clears the display's event queue. |
| * Same as calling <code>getTestFixture().flushEventQueue()</code> |
| */ |
| protected void flushEventQueue() { |
| getTestFixture().flushEventQueue(); |
| } |
| |
| /** Same as calling <code>getTestFixture().tearDown()</code>. */ |
| protected void tearDown() throws Exception { |
| |
| flushEventQueue(); |
| getTestFixture().tearDown(); |
| } |
| |
| /** |
| * Creates a new shape view as a child of the diagram at the given location |
| * @param editor |
| * @param semanticElement |
| * @param location |
| * @return IShapeView |
| * @deprecated use createShapeView(IDiagramWorkbenchPart,Eobject,Point) |
| */ |
| /* |
| protected IShapeView createShapeView( |
| IDiagramWorkbenchPart editor, |
| IElement semanticElement, |
| Point location) { |
| |
| CompoundCommand cc = new CompoundCommand(); |
| |
| CreateViewRequest request = new CreateViewRequest(semanticElement); |
| request.setLocation(location); |
| |
| cc.add(editor.getDiagramEditPart().getCommand(request)); |
| |
| RefreshConnectorsRequest rcRequest = |
| new RefreshConnectorsRequest(request.getNewObject()); |
| cc.add( |
| getDiagramWorkbenchPart().getDiagramEditPart().getCommand( |
| rcRequest)); |
| |
| getCommandStack().execute(cc); |
| |
| return (IShapeView) |
| ((IAdaptable) (request.getNewObject()).get(0)).getAdapter( |
| IShapeView.class); |
| } |
| */ |
| |
| /** |
| * Creates a new shape view as a child of the diagram at the given location |
| * @param editor |
| * @param semanticElement |
| * @param location |
| * @return IShapeView |
| */ |
| protected View createShapeView( |
| DiagramEditPart diagramEP, |
| EObject semanticElement, |
| Point location) { |
| |
| CompoundCommand cc = new CompoundCommand(); |
| |
| CreateViewRequest request = new CreateViewRequest(semanticElement, |
| getTestFixture().getPreferencesHint()); |
| request.setLocation(location); |
| |
| cc.add(diagramEP.getCommand(request)); |
| |
| RefreshConnectionsRequest rcRequest = |
| new RefreshConnectionsRequest((List)request.getNewObject()); |
| cc.add(getDiagramEditPart().getCommand(rcRequest)); |
| |
| getCommandStack().execute(cc); |
| |
| return (View) |
| ((IAdaptable) ((List)request.getNewObject()).get(0)).getAdapter( |
| View.class); |
| } |
| |
| protected void clearDiagram() { |
| testAction(SelectAllAction.createSelectAllAction(getWorkbenchPage()), null); |
| |
| testAction( |
| GlobalActionManager.getInstance().createActionHandler( |
| getWorkbenchPage(), |
| GlobalActionId.DELETE), null); |
| } |
| |
| /** |
| * Return the figure in which elements are being added to. |
| * @return <code>getDiagramEditPart().getFigure()</code>. |
| */ |
| protected IFigure getDrawSurfaceFigure() { |
| return getDiagramEditPart().getFigure(); |
| } |
| |
| /** |
| * Return the editpart in which elements are being added to. |
| * @return <code>getDiagramEditPart()</code>. |
| */ |
| protected IGraphicalEditPart getDrawSurfaceEditPart() { |
| return getDiagramEditPart(); |
| } |
| |
| |
| /** Return the supplied editpart's {@link ShapeNodeEditPart}children. */ |
| protected List getShapesIn(IGraphicalEditPart parent) { |
| assertNotNull(parent); |
| List shapes = new ArrayList(); |
| |
| Iterator it = parent.getChildren().iterator(); |
| while (it.hasNext()) { |
| Object child = it.next(); |
| if (child instanceof ShapeNodeEditPart) { |
| shapes.add(child); |
| } |
| } |
| return shapes; |
| } |
| |
| /** Return <code>getDiagramEditPart().getConnectors()</code>. */ |
| protected List getConnectors() { |
| return getDiagramEditPart().getConnections(); |
| } |
| |
| /* Will run teardown if the setup fails. |
| * @see junit.framework.TestCase#runBare() |
| */ |
| public void runBare() |
| throws Throwable { |
| |
| try { |
| setUp(); |
| runTest(); |
| } |
| finally { |
| tearDown(); |
| } |
| } |
| |
| /** |
| * Reorients the connection to a new target. |
| * |
| * @param connectionEditPart |
| * the connection editpart to be reoriented |
| * @param targetEditPart |
| * the new target editpart |
| * @param supported |
| * should this gesture be supported? |
| * @return the command that was executed |
| */ |
| protected Command reorientConnectionTarget( |
| final ConnectionEditPart connectionEditPart, |
| final IGraphicalEditPart targetEditPart, boolean supported) { |
| ReconnectRequest reconnectReq = new ReconnectRequest( |
| RequestConstants.REQ_RECONNECT_TARGET); |
| reconnectReq.setConnectionEditPart(connectionEditPart); |
| reconnectReq.setTargetEditPart(targetEditPart); |
| reconnectReq.setLocation(targetEditPart.getFigure().getBounds() |
| .getTopRight()); |
| Command cmd = targetEditPart.getCommand(reconnectReq); |
| if (supported) { |
| testCommand(cmd, new ITestCommandCallback() { |
| |
| public void onCommandExecution() { |
| assertTrue(connectionEditPart.getTarget() == targetEditPart); |
| } |
| }); |
| } else { |
| assertTrue(cmd == null || !cmd.canExecute()); |
| } |
| return cmd; |
| } |
| |
| /** |
| * Reorients the connection to a new source. |
| * |
| * @param connectionEditPart |
| * the connection editpart to be reoriented |
| * @param sourceEditPart |
| * the new source editpart |
| * @param supported |
| * should this gesture be supported? |
| * @return the command that was executed |
| */ |
| protected Command reorientConnectionSource( |
| final ConnectionEditPart connectionEditPart, |
| final IGraphicalEditPart sourceEditPart, boolean supported) { |
| ReconnectRequest reconnectReq = new ReconnectRequest( |
| RequestConstants.REQ_RECONNECT_SOURCE); |
| reconnectReq.setConnectionEditPart(connectionEditPart); |
| reconnectReq.setTargetEditPart(sourceEditPart); |
| reconnectReq.setLocation(sourceEditPart.getFigure().getBounds() |
| .getTopRight()); |
| Command cmd = sourceEditPart.getCommand(reconnectReq); |
| if (supported) { |
| testCommand(cmd, new ITestCommandCallback() { |
| |
| public void onCommandExecution() { |
| assertTrue(connectionEditPart.getSource() == sourceEditPart); |
| } |
| }); |
| } else { |
| assertTrue(cmd == null || !cmd.canExecute()); |
| } |
| return cmd; |
| } |
| } |