| /******************************************************************************* |
| * Copyright (c) 2003, 2010 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.draw2d.test; |
| |
| import java.lang.reflect.Field; |
| import java.util.ArrayList; |
| |
| import junit.framework.TestCase; |
| |
| import org.eclipse.draw2d.graph.DirectedGraph; |
| import org.eclipse.draw2d.graph.DirectedGraphLayout; |
| import org.eclipse.draw2d.graph.Edge; |
| import org.eclipse.draw2d.graph.Node; |
| import org.eclipse.draw2d.graph.Rank; |
| |
| /** |
| * Tests the swapping of adjacent nodes in a directed graph. since 3.0 |
| * |
| */ |
| public class LocalOptimizerTest extends TestCase { |
| |
| private DirectedGraph graph; |
| private Node a, b, c, d, e, f, g, h, i, j, k, l; |
| |
| /* |
| * @see TestCase#setUp() |
| */ |
| protected void setUp() throws Exception { |
| super.setUp(); |
| |
| graph = new DirectedGraph(); |
| |
| // create nodes and populate their ranks |
| a = createNode("a"); |
| b = createNode("b"); |
| c = createNode("c"); |
| d = createNode("d"); |
| e = createNode("e"); |
| f = createNode("f"); |
| g = createNode("g"); |
| h = createNode("h"); |
| i = createNode("i"); |
| j = createNode("j"); |
| k = createNode("k"); |
| l = createNode("l"); |
| |
| rankNodes(new Node[] { a, b, c, d }, 0); |
| rankNodes(new Node[] { e, f, g, h }, 1); |
| rankNodes(new Node[] { i, j, k, l }, 2); |
| |
| createDirectedGraphLayoutWithSelectedStepOnly( |
| new String[] { "org.eclipse.draw2d.graph.PopulateRanks" }) |
| .visit(graph); |
| } |
| |
| /* |
| * @see TestCase#tearDown() |
| */ |
| protected void tearDown() throws Exception { |
| super.tearDown(); |
| } |
| |
| public void testIncomingSwapNeeded() { |
| /* |
| * A B C D |\| \ | | X \| | |\ | E F G H |
| */ |
| createEdge(a, e); |
| createEdge(b, f); |
| createEdge(a, g); |
| createEdge(c, h); |
| createEdge(d, h); |
| |
| createDirectedGraphLayoutWithSelectedStepOnly( |
| new String[] { "org.eclipse.draw2d.graph.LocalOptimizer" }) |
| .visit(graph); |
| |
| checkResults(new Node[][] { new Node[] { a, b, c, d }, |
| new Node[] { e, g, f, h } }); |
| } |
| |
| public void testOutgoingSwapNeeded() { |
| /* |
| * A BC D \ | X \|/ \ E F G H |
| */ |
| createEdge(a, f); |
| createEdge(b, f); |
| createEdge(d, f); |
| createEdge(c, h); |
| |
| createDirectedGraphLayoutWithSelectedStepOnly( |
| new String[] { "org.eclipse.draw2d.graph.LocalOptimizer" }) |
| .visit(graph); |
| |
| checkResults(new Node[][] { new Node[] { a, b, d, c }, |
| new Node[] { e, f, g, h } }); |
| } |
| |
| public void testIncomingOffsetSwapNeeded() { |
| /* |
| * A B C (C should swap twice to first position) \ \ / \ X X \ / \ \ |
| * [-----E----] F G H \ / / \ / / X / / \ / I J K L (Should not swap) |
| */ |
| createEdge(a, e); |
| createEdge(b, e).offsetTarget = 30; |
| createEdge(c, e).offsetTarget = 20; |
| |
| createEdge(e, k).offsetSource = 20; |
| createEdge(e, j).offsetSource = 30; |
| createEdge(f, k); |
| |
| createDirectedGraphLayoutWithSelectedStepOnly( |
| new String[] { "org.eclipse.draw2d.graph.LocalOptimizer" }) |
| .visit(graph); |
| |
| checkResults(new Node[][] { new Node[] { c, a, b, d }, |
| new Node[] { e, f, g, h }, new Node[] { i, j, k, l } }); |
| } |
| |
| public void testBidirectionalSwapNeeded() { |
| /* |
| * A B C D \ |\ \| \ E F G H (F and G should swap) X| / X | |\ I J K L |
| * |
| * |
| * A B C D (Which causes A&B on previous rank to swap) \ /| X | / \| E G |
| * F H |\ \ | \ \ I J K L |
| */ |
| createEdge(a, f); |
| createEdge(b, f); |
| createEdge(b, g); |
| createEdge(f, l); |
| createEdge(g, j); |
| createEdge(g, k); |
| |
| createDirectedGraphLayoutWithSelectedStepOnly( |
| new String[] { "org.eclipse.draw2d.graph.LocalOptimizer" }) |
| .visit(graph); |
| |
| checkResults(new Node[][] { new Node[] { b, a, c, d }, |
| new Node[] { e, g, f, h }, new Node[] { i, j, k, l } }); |
| } |
| |
| /** |
| * LocalOptimizer and other GraphVisitors are package private, so we cannot |
| * instantiate them directly. Instead, we use a DirectedGraphLayout and |
| * remove all other steps from it. |
| * |
| * @return A DirectedGraphLayout containing only the selected steps. |
| */ |
| private DirectedGraphLayout createDirectedGraphLayoutWithSelectedStepOnly( |
| String[] graphVisitorClassNames) { |
| try { |
| DirectedGraphLayout layout = new DirectedGraphLayout(); |
| Field stepsField = DirectedGraphLayout.class |
| .getDeclaredField("steps"); |
| stepsField.setAccessible(true); |
| ArrayList steps = (ArrayList) stepsField.get(layout); |
| ArrayList filteredSteps = new ArrayList(); |
| for (int i = 0; i < steps.size(); i++) { |
| Object graphVisitor = steps.get(i); |
| for (int j = 0; j < graphVisitorClassNames.length; j++) { |
| if (graphVisitorClassNames[j].equals(graphVisitor |
| .getClass().getName())) { |
| filteredSteps.add(graphVisitor); |
| } |
| } |
| } |
| assertEquals(graphVisitorClassNames.length, filteredSteps.size()); |
| stepsField.set(layout, filteredSteps); |
| return layout; |
| } catch (Exception e) { |
| fail(e.getMessage()); |
| return null; |
| } |
| } |
| |
| private Node createNode(String label) { |
| Node node = new Node(label); |
| graph.nodes.add(node); |
| return node; |
| } |
| |
| private Edge createEdge(Node n1, Node n2) { |
| Edge edge = new Edge(n1, n2); |
| graph.edges.add(edge); |
| return edge; |
| } |
| |
| private void rankNodes(Node[] nodes, int rank) { |
| for (int i = 0; i < nodes.length; i++) { |
| Node node = nodes[i]; |
| try { |
| // node.rank = rank; |
| Field rankField = Node.class.getDeclaredField("rank"); |
| rankField.setAccessible(true); |
| rankField.set(node, new Integer(rank)); |
| // node.index = i; |
| Field indexField = Node.class.getDeclaredField("index"); |
| indexField.setAccessible(true); |
| indexField.set(node, new Integer(i)); |
| } catch (Exception e) { |
| fail(e.getMessage()); |
| } |
| } |
| } |
| |
| private void checkResults(Node[][] nodes) { |
| for (int r = 0; r < nodes.length; r++) { |
| Node[] row = nodes[r]; |
| Rank rank = graph.ranks.getRank(r); |
| assertEquals(rank.size(), row.length); |
| for (int n = 0; n < row.length; n++) { |
| Node node = row[n]; |
| assertEquals("Unexpected node encountered at:" + r + "," + n, |
| node, rank.getNode(n)); |
| } |
| } |
| } |
| } |