package net.sourceforge.mayfly.graph; import junit.framework.TestCase; import junitx.framework.StringAssert; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.SortedSet; public class GraphTest extends TestCase { private Graph graph; private StringNode a; private StringNode b; private StringNode c; private StringNode d; private StringNode e; public GraphTest() { graph = new Graph(); a = new StringNode("a"); b = new StringNode("b"); c = new StringNode("c"); d = new StringNode("d"); e = new StringNode("e"); } public void testEmpty() throws Exception { assertEquals(0, graph.nodeCount()); } public void testAddNode() throws Exception { graph.addNode(new StringNode("a")); assertEquals(1, graph.nodeCount()); graph.addNode(new StringNode("b")); assertEquals(2, graph.nodeCount()); } public void testDuplicateNode() throws Exception { graph.addNode(a); try { graph.addNode(a); fail(); } catch (RuntimeException e) { StringAssert.assertStartsWith("already have node ", e.getMessage()); } } public void testBackupCompareIsZero() throws Exception { graph.addNode(new StringNode("a")); try { graph.addNode(new StringNode("a")); fail(); } catch (RuntimeException e) { StringAssert.assertStartsWith("already have node ", e.getMessage()); } } public void testAddEdge() throws Exception { graph.addNode(a); graph.addNode(b); graph.addEdge(a, b); assertEquals(0, graph.predecessors(a).size()); SortedSet bPredecessors = graph.predecessors(b); assertEquals(1, bPredecessors.size()); assertSame(a, bPredecessors.iterator().next()); assertEquals(0, graph.successors(b).size()); SortedSet aSuccessors = graph.successors(a); assertEquals(1, aSuccessors.size()); assertSame(b, aSuccessors.iterator().next()); } public void testAddEdgeAgainIsNoop() throws Exception { graph.addNode(a); graph.addNode(b); graph.addEdge(a, b); graph.addEdge(a, b); assertEquals(0, graph.predecessors(a).size()); SortedSet bPredecessors = graph.predecessors(b); assertEquals(1, bPredecessors.size()); assertSame(a, bPredecessors.iterator().next()); assertEquals(0, graph.successors(b).size()); SortedSet aSuccessors = graph.successors(a); assertEquals(1, aSuccessors.size()); assertSame(b, aSuccessors.iterator().next()); } public void testRemoveEdge() throws Exception { graph.addNode(a); graph.addNode(b); graph.addEdge(a, b); graph.removeEdge(a, b); assertEquals(0, graph.predecessors(a).size()); assertEquals(0, graph.predecessors(b).size()); assertEquals(0, graph.successors(a).size()); assertEquals(0, graph.successors(b).size()); } public void testRemoveNonexistentEdge() throws Exception { graph.addNode(a); graph.addNode(b); try { graph.removeEdge(a, b); fail(); } catch (RuntimeException e) { StringAssert.assertStartsWith( "there was no edge from ", e.getMessage()); } } public void testNodesWithNoPredecessor() throws Exception { graph.addNode(a); graph.addNode(b); graph.addEdge(a, b); SortedSet initialNodes = graph.nodesWithNoPredecessor(); assertEquals(1, initialNodes.size()); assertSame(a, initialNodes.iterator().next()); } public void testSortingOfInitialNodes() throws Exception { graph.addNode(a); graph.addNode(e); graph.addNode(d); graph.addNode(b); graph.addNode(c); graph.addEdge(a, b); Iterator initialNodes = graph.nodesWithNoPredecessor().iterator(); assertSame(a, initialNodes.next()); assertSame(c, initialNodes.next()); assertSame(d, initialNodes.next()); assertSame(e, initialNodes.next()); assertFalse(initialNodes.hasNext()); } public void testTopologicalSort() throws Exception { graph.addNode(a); graph.addNode(b); graph.addNode(c); graph.addNode(d); graph.addEdge(d, b); graph.addEdge(c, b); graph.addEdge(b, a); Iterator sorted = graph.topologicalSort().iterator(); assertSame(c, sorted.next()); assertSame(d, sorted.next()); assertSame(b, sorted.next()); assertSame(a, sorted.next()); assertFalse(sorted.hasNext()); } public void testTopologicalSortWithCycle() throws Exception { graph.addNode(a); graph.addNode(b); graph.addNode(c); graph.addNode(d); graph.addEdge(d, b); graph.addEdge(c, b); graph.addEdge(b, a); graph.addEdge(a, d); try { graph.topologicalSort(); fail(); } catch (CycleDetectedException e) { /* Ideally, this would (a) list all the members of one cycle, or perhaps an abbreviated version if there are many, and (b) be re-worded for the specific graph (perhaps by having the CycleDetectedException contain references to the nodes in the cycle, and letting the caller catch and rethrow). */ assertEquals("graph contains a cycle", e.getMessage()); } } public void testRanOutOfNodes() throws Exception { try { graph.sortStep(new ArrayList(), Collections.EMPTY_LIST); fail(); } catch (CycleDetectedException e) { assertEquals("graph contains a cycle", e.getMessage()); } } public void testNoSuccessors() throws Exception { graph.addNode(a); ArrayList queue = new ArrayList(); queue.add(a); ArrayList result = new ArrayList(); graph.sortStep(result, queue); assertEquals(1, result.size()); assertSame(a, result.get(0)); assertEquals(0, queue.size()); } public void testSuccessorHasOtherPredecessors() throws Exception { graph.addNode(a); graph.addNode(b); graph.addNode(c); graph.addEdge(a, c); graph.addEdge(b, c); ArrayList queue = new ArrayList(); queue.add(a); queue.add(b); ArrayList result = new ArrayList(); graph.sortStep(result, queue); assertEquals(1, result.size()); assertSame(a, result.get(0)); assertEquals(1, queue.size()); assertSame(b, queue.get(0)); Iterator cPredecessors = graph.predecessors(c).iterator(); assertSame(b, cPredecessors.next()); assertFalse(cPredecessors.hasNext()); } public void testMoveSuccessorsToQueue() throws Exception { graph.addNode(a); graph.addNode(b); graph.addNode(c); graph.addEdge(a, b); graph.addEdge(a, c); ArrayList queue = new ArrayList(); queue.add(a); ArrayList result = new ArrayList(); graph.sortStep(result, queue); assertEquals(1, result.size()); assertSame(a, result.get(0)); assertEquals(2, queue.size()); assertSame(b, queue.get(0)); assertSame(c, queue.get(1)); assertEquals(0, graph.predecessors(c).size()); assertEquals(0, graph.predecessors(b).size()); } }