Java tutorial
/** * This program and the accompanying materials * are made available under the terms of the License * which accompanies this distribution in the file LICENSE.txt */ package com.archimatetool.editor.views.tree; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import junit.framework.JUnit4TestAdapter; import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.DropTargetListener; import org.eclipse.swt.widgets.TreeItem; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import com.archimatetool.editor.ArchimateTestModel; import com.archimatetool.model.FolderType; import com.archimatetool.model.IArchimateElement; import com.archimatetool.model.IArchimateFactory; import com.archimatetool.model.IArchimateModel; import com.archimatetool.model.IFolder; /** * This is an example of overkill in the world of Unit Tests. * It uses Mockito's mock objects */ @RunWith(MockitoJUnitRunner.class) public class TreeModelViewerDragDropHandlerTests { private ArchimateTestModel tm; private IArchimateModel model; // The real TreeModelViewerDragDropHandler to test private TreeModelViewerDragDropHandler dragHandler; @Mock private TreeViewer treeViewer; // Mock the TreeViewer public static junit.framework.Test suite() { return new JUnit4TestAdapter(TreeModelViewerDragDropHandlerTests.class); } @Before public void runOnceBeforeEachTest() { tm = new ArchimateTestModel(); model = tm.createNewModel(); // We need a real model and Command Stack for some operations dragHandler = new TreeModelViewerDragDropHandler(treeViewer); } @Test public void verifyDragHandlerRegisteredDragSupport() { // Verify treeViewer added drag support verify(treeViewer).addDragSupport(eq(DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK), eq(dragHandler.sourceTransferTypes), any(DragSourceListener.class)); } @Test public void verifyDragHandlerRegisteredDropSupport() { // Verify treeViewer added drop support verify(treeViewer).addDropSupport(eq(DND.DROP_MOVE), eq(dragHandler.targetTransferTypes), any(DropTargetListener.class)); } @Test public void testIsValidTreeSelection() { // Null selection is not valid StructuredSelection selection = null; assertFalse(dragHandler.isValidTreeSelection(selection)); // Set up some data IFolder userFolder = IArchimateFactory.eINSTANCE.createFolder(); model.getFolder(FolderType.DIAGRAMS).getFolders().add(userFolder); IFolder businessFolder = model.getFolder(FolderType.BUSINESS); IArchimateElement e1 = IArchimateFactory.eINSTANCE.createBusinessActor(); businessFolder.getElements().add(e1); IArchimateElement e2 = IArchimateFactory.eINSTANCE.createBusinessActor(); businessFolder.getElements().add(e2); // Elements from the same root parent are OK selection = new StructuredSelection(new Object[] { e1, e2 }); assertTrue(dragHandler.isValidTreeSelection(selection)); // Can't DnD a model selection = new StructuredSelection(new Object[] { model }); assertFalse(dragHandler.isValidTreeSelection(selection)); // Can DnD a user folder selection = new StructuredSelection(new Object[] { userFolder }); assertTrue(dragHandler.isValidTreeSelection(selection)); // Can't DnD a system folder selection = new StructuredSelection(new Object[] { businessFolder }); assertFalse(dragHandler.isValidTreeSelection(selection)); // Can't DnD Mixed parent models IArchimateModel model2 = IArchimateFactory.eINSTANCE.createArchimateModel(); model2.setDefaults(); IArchimateElement e3 = IArchimateFactory.eINSTANCE.createBusinessActor(); model2.getFolder(FolderType.BUSINESS).getElements().add(e3); selection = new StructuredSelection(new Object[] { e1, e3 }); assertFalse(dragHandler.isValidTreeSelection(selection)); } @Test public void testDoDropOperation() { // Source IFolder sourceParentFolder = model.getFolder(FolderType.BUSINESS); IArchimateElement childElement = IArchimateFactory.eINSTANCE.createBusinessActor(); sourceParentFolder.getElements().add(childElement); assertTrue(sourceParentFolder.getElements().contains(childElement)); // Target IFolder targetParentFolder = model.getFolder(FolderType.APPLICATION); assertTrue(targetParentFolder.getElements().isEmpty()); assertTrue(targetParentFolder.getFolders().isEmpty()); // Set up a mock DropTargetEvent for the DropOperation DropTargetEvent event = createMockDropTargetEvent(targetParentFolder); // Set the selection of elements we want to DnD LocalSelectionTransfer.getTransfer().setSelection(new StructuredSelection(new Object[] { childElement })); // And call the drop method dragHandler.doDropOperation(event); assertTrue(sourceParentFolder.getElements().isEmpty()); assertTrue(targetParentFolder.getElements().contains(childElement)); } /** * The famous DnD bug of drag and dropping a child folder onto its parent (fixed in Archi 2.4.1) */ @Test public void moveTreeObjects_DropChildFolderOntoSameParentIsSame() { // Add a child folder to a parent folder IFolder parentFolder = model.getFolder(FolderType.BUSINESS); IFolder childFolder = IArchimateFactory.eINSTANCE.createFolder(); parentFolder.getFolders().add(childFolder); // Check all is well assertEquals(1, parentFolder.getFolders().size()); assertTrue(parentFolder.getFolders().contains(childFolder)); assertTrue(parentFolder.getElements().isEmpty()); // Move child folder to the same target parent folder dragHandler.moveTreeObjects(parentFolder, new Object[] { childFolder }); // Should be the same assertEquals(1, parentFolder.getFolders().size()); assertTrue(parentFolder.getFolders().contains(childFolder)); // Elements should not be affected assertTrue(parentFolder.getElements().isEmpty()); } /** * Drag and dropping a folder onto a different parent */ @Test public void moveTreeObjects_DropChildFolderOntoDifferentParent() { // Add a child folder to a parent folder IFolder sourceParentFolder = model.getFolder(FolderType.BUSINESS); IFolder childFolder = IArchimateFactory.eINSTANCE.createFolder(); sourceParentFolder.getFolders().add(childFolder); // Check all is well assertEquals(1, sourceParentFolder.getFolders().size()); assertTrue(sourceParentFolder.getFolders().contains(childFolder)); // New target parent folder IFolder targetParentFolder = model.getFolder(FolderType.APPLICATION); assertTrue(targetParentFolder.getFolders().isEmpty()); assertTrue(targetParentFolder.getElements().isEmpty()); // Move child folder to the different target parent folder dragHandler.moveTreeObjects(targetParentFolder, new Object[] { childFolder }); // Source should be empty assertTrue(sourceParentFolder.getFolders().isEmpty()); // Target should be populated assertEquals(1, targetParentFolder.getFolders().size()); assertEquals(childFolder, targetParentFolder.getFolders().get(0)); // Elements should not be affected assertTrue(targetParentFolder.getElements().isEmpty()); } /** * Drag and dropping child elements onto same parent */ @Test public void moveTreeObjects_DropChildElementsOntoSameParentIsSame() { // Add child elements to a folder IFolder parentFolder = model.getFolder(FolderType.BUSINESS); IArchimateElement childElement1 = IArchimateFactory.eINSTANCE.createBusinessActor(); parentFolder.getElements().add(childElement1); IArchimateElement childElement2 = IArchimateFactory.eINSTANCE.createBusinessActor(); parentFolder.getElements().add(childElement2); // Check all is well assertTrue(parentFolder.getFolders().isEmpty()); assertEquals(2, parentFolder.getElements().size()); assertEquals(childElement1, parentFolder.getElements().get(0)); assertEquals(childElement2, parentFolder.getElements().get(1)); // Move child elements to the same parent folder dragHandler.moveTreeObjects(parentFolder, new Object[] { childElement1, childElement2 }); // Shouldn't affect folders assertTrue(parentFolder.getFolders().isEmpty()); // Should be the same assertEquals(2, parentFolder.getElements().size()); assertEquals(childElement1, parentFolder.getElements().get(0)); assertEquals(childElement2, parentFolder.getElements().get(1)); } /** * Drag and dropping child elements onto different parent */ @Test public void moveTreeObjects_DropChildElementsOntoDifferentParent() { // Add child elements to a folder IFolder sourceParentFolder = model.getFolder(FolderType.BUSINESS); IArchimateElement childElement1 = IArchimateFactory.eINSTANCE.createBusinessActor(); sourceParentFolder.getElements().add(childElement1); IArchimateElement childElement2 = IArchimateFactory.eINSTANCE.createBusinessActor(); sourceParentFolder.getElements().add(childElement2); // Check all is well assertEquals(2, sourceParentFolder.getElements().size()); assertEquals(childElement1, sourceParentFolder.getElements().get(0)); assertEquals(childElement2, sourceParentFolder.getElements().get(1)); // New target parent folder and all is well IFolder targetParentFolder = model.getFolder(FolderType.APPLICATION); assertTrue(targetParentFolder.getFolders().isEmpty()); assertTrue(targetParentFolder.getElements().isEmpty()); // Move child element to the different target parent folder dragHandler.moveTreeObjects(targetParentFolder, new Object[] { childElement1, childElement2 }); // Source should be empty assertTrue(sourceParentFolder.getElements().isEmpty()); // Shouldn't affect folders assertEquals(2, targetParentFolder.getElements().size()); // Target should be populated assertEquals(childElement1, targetParentFolder.getElements().get(0)); assertEquals(childElement2, targetParentFolder.getElements().get(1)); assertTrue(targetParentFolder.getFolders().isEmpty()); } @Test public void testGetTargetParent() { // A Folder is ok Object target = IArchimateFactory.eINSTANCE.createFolder(); DropTargetEvent event = createMockDropTargetEvent(target); assertEquals(target, dragHandler.getTargetParent(event)); // Anything else is not OK target = IArchimateFactory.eINSTANCE.createBusinessActor(); event = createMockDropTargetEvent(target); assertNull(dragHandler.getTargetParent(event)); // Simulate dropping on blank area of tree event.item = null; assertNull(dragHandler.getTargetParent(event)); } @Test public void testIsValidDropTarget() { IFolder folder = IArchimateFactory.eINSTANCE.createFolder(); IArchimateElement childElement = IArchimateFactory.eINSTANCE.createBusinessActor(); folder.getElements().add(childElement); LocalSelectionTransfer.getTransfer().setSelection(new StructuredSelection(new Object[] { childElement })); // Can only drop onto a folder DropTargetEvent event = createMockDropTargetEvent(folder); assertTrue(dragHandler.isValidDropTarget(event)); // And not something else event = createMockDropTargetEvent(childElement); assertFalse(dragHandler.isValidDropTarget(event)); } @Test public void testHasCommonAncestorFolder() { // Test with folders and elements that have a root model IFolder businessFolder = model.getFolder(FolderType.BUSINESS); IFolder appFolder = model.getFolder(FolderType.APPLICATION); __doTestHasCommonAncestorFolderWithTheseFolders(businessFolder, appFolder); // Test with folders and elements that have no root model IFolder parent1 = IArchimateFactory.eINSTANCE.createFolder(); IFolder parent2 = IArchimateFactory.eINSTANCE.createFolder(); __doTestHasCommonAncestorFolderWithTheseFolders(parent1, parent2); } private void __doTestHasCommonAncestorFolderWithTheseFolders(IFolder parentFolder1, IFolder parentFolder2) { /* businessFolder |-- f2 |-- e1 |-- f3 |-- e2 appFolder |-- f4 |-- e3 |-- f5 |-- e4 */ IFolder f2 = IArchimateFactory.eINSTANCE.createFolder(); IFolder f3 = IArchimateFactory.eINSTANCE.createFolder(); parentFolder1.getFolders().add(f2); parentFolder1.getFolders().add(f3); IArchimateElement e1 = IArchimateFactory.eINSTANCE.createBusinessActor(); f2.getElements().add(e1); IArchimateElement e2 = IArchimateFactory.eINSTANCE.createBusinessActor(); f3.getElements().add(e2); IFolder f4 = IArchimateFactory.eINSTANCE.createFolder(); IFolder f5 = IArchimateFactory.eINSTANCE.createFolder(); parentFolder2.getFolders().add(f4); parentFolder2.getFolders().add(f5); IArchimateElement e3 = IArchimateFactory.eINSTANCE.createApplicationComponent(); f4.getElements().add(e3); IArchimateElement e4 = IArchimateFactory.eINSTANCE.createApplicationComponent(); f5.getElements().add(e4); // Same common ancestor assertTrue(dragHandler.hasCommonAncestorFolder(f2, f3)); assertTrue(dragHandler.hasCommonAncestorFolder(f2, e1)); assertTrue(dragHandler.hasCommonAncestorFolder(f3, e1)); assertTrue(dragHandler.hasCommonAncestorFolder(e1, e2)); // Different common ancestors assertFalse(dragHandler.hasCommonAncestorFolder(f2, f4)); assertFalse(dragHandler.hasCommonAncestorFolder(f3, f5)); assertFalse(dragHandler.hasCommonAncestorFolder(f3, e3)); assertFalse(dragHandler.hasCommonAncestorFolder(e1, e4)); } @Test public void testCanDropObject() { IArchimateElement e1 = IArchimateFactory.eINSTANCE.createBusinessActor(); IArchimateElement e2 = IArchimateFactory.eINSTANCE.createBusinessActor(); // Null tree item is no good assertFalse(dragHandler.canDropObject(e1, null)); // Cannot drop onto itself DropTargetEvent event = createMockDropTargetEvent(e1); assertFalse(dragHandler.canDropObject(e1, (TreeItem) event.item)); // OK assertTrue(dragHandler.canDropObject(e2, (TreeItem) event.item)); // Can't test "If moving a folder check that target folder is not a descendant of the source folder" // Because parent tree items are created by the system } // ==================================================================================================== /** * Create a mock DropTargetEvent */ private DropTargetEvent createMockDropTargetEvent(Object target) { DropTargetEvent event = mock(DropTargetEvent.class); // Set event type to LocalSelectionTransfer type event.currentDataType = LocalSelectionTransfer.getTransfer().getSupportedTypes()[0]; // Set item to a mock tree item event.item = mock(TreeItem.class); // The mock item should return the target when(event.item.getData()).thenReturn(target); return event; } }