blob: b4e79efabfc38f8658616e96393a2d4e40ac3144 [file] [log] [blame]
/*******************************************************************************
* 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));
}
}
}
}