/*
* EuroCarbDB, a framework for carbohydrate bioinformatics
*
* Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
* A copy of this license accompanies this distribution in the file LICENSE.txt.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* Last commit: $Rev: 1147 $ by $Author: glycoslave $ on $Date:: 2009-06-04 #$
*/
package test.eurocarbdb.util.graph;
import java.util.*;
import org.apache.log4j.Logger;
import org.apache.log4j.Level;
import org.testng.annotations.*;
import org.eurocarbdb.util.graph.*;
import static java.lang.System.out;
import static org.eurocarbdb.util.StringUtils.join;
@Test( groups="util.graphs", sequential=true, timeOut=2000 )
/**
* Tests fundamental operation of {@link Graph} class.
*/
public class GraphTest
{
/**
* contains the following graph, once populated:
*<pre>
* F
* \
* E -- C
* / \
* G B -- A
* /
* H -- D
*
*</pre>
*/
protected Graph<Integer,Character> tree;
protected Graph<Float, String> g1;
protected Graph<Float, String> g2;
@BeforeTest
public void setupLogging()
{
Logger.getLogger("org.eurocarbdb.util.graph").setLevel( Level.ALL );
}
@Test
/** Constructs empty graph, g1 */
public void graphInitialConstruction()
{
g1 = new Graph<Float,String>();
assert g1 != null;
assert g1.size() == 0;
assert g1.getAllVertices() != null;
assert g1.getAllVertices().size() == 0;
assert g1.getAllEdges() != null;
assert g1.getAllEdges().size() == 0;
Collection<String> values = g1.getAllVertexValues();
assert values != null;
assert values.size() == 0;
out.println("Constructed zero-size graph:");
out.println( g1 );
}
@Test( dependsOnMethods = {"graphInitialConstruction"} )
/**
* Populates variable {@link #tree}, the test graph created is:
*<pre>
* F
* \
* E -- C
* / \
* G B -- A
* /
* H -- D
*
*</pre>
*/
public void graphAdditionOfVerticesAndEdges()
{
tree = new Graph<Integer,Character>();
tree.addVertex('A');
tree.addVertex('B');
tree.addVertex('C');
tree.addVertex('D');
tree.addVertex('E');
tree.addVertex('F');
tree.addVertex('G');
tree.addVertex('H');
tree.addEdge('A', 'B');
tree.addEdge('B', 'C');
tree.addEdge('C', 'E');
tree.addEdge('E', 'F');
tree.addEdge('E', 'G');
tree.addEdge('B', 'D');
tree.addEdge('D', 'H');
out.println("tree:");
out.println( tree.toString() );
// sanity check graph size
assert tree.size() == 8;
assert tree.countEdges() == 7;
assert tree.countVertices() == 8;
// check #edges for each vertex conforms to expected number
countEdgesOf( 'A', 1 );
countEdgesOf( 'B', 3 );
countEdgesOf( 'C', 2 );
countEdgesOf( 'D', 2 );
countEdgesOf( 'E', 3 );
countEdgesOf( 'F', 1 );
countEdgesOf( 'G', 1 );
countEdgesOf( 'H', 1 );
}
final void countEdgesOf( char vertex, int expected_nmb_edges )
{
out.println(
"expected "
+ expected_nmb_edges
+ " edge(s) for vertex '"
+ vertex
+ "', observed: "
+ join(", ", tree.getVertex( vertex ).getAttachedEdges())
);
assert tree.getVertex( vertex ).countAttachedEdges() == expected_nmb_edges;
assert tree.getVertex( vertex ).countAttachedVertices() == expected_nmb_edges;
}
@Test( dependsOnMethods = {"graphInitialConstruction"} )
/**
* populates graph g1:
*<pre>
* vertex1 --- 0.75 --> vertex2 --- 0.25 ---> vertex3
* |
* 0.1
* |
* \|/
* vertex4
*</pre>
* graph is circularised in method 'graphCircularise'
*/
public void graphAdditionOfVerticesAndEdgesWithValues()
{
// 1 Vertex
//
// vertex1
//
out.println( "adding first vertex: vertex1" );
g1.addVertex( "vertex1" );
out.println( "last vertex added was " + g1.lastVertex() );
out.println( "graph is now:" );
out.println( g1 );
out.println();
assert g1.lastVertex().getValue() == "vertex1";
assert g1.size() == 1;
assert g1.lastVertex().getIncomingEdges().size() == 0;
assert g1.lastVertex().getOutgoingEdges().size() == 0;
// add 1 vertex + 1 edge; total 2 vertices, 1 edge.
//
// vertex1 --- 0.75 --> vertex2
//
g1.addPath( g1.lastVertex(), 0.75f, "vertex2" );
out.println( "last vertex added was " + g1.lastVertex() );
out.println( "graph is now:" );
out.println( g1 );
out.println();
assert g1.size() == 2;
assert g1.countEdges() == 1;
assert g1.countVertices() == 2;
assert g1.lastVertex().getValue() == "vertex2";
assert g1.lastVertex().getIncomingEdges().size() == 1;
assert g1.lastVertex().getOutgoingEdges().size() == 0;
// add another vertex + edge; total 3 vertices, 2 edges.
//
// vertex1 --- 0.75 --> vertex2 --- 0.25 ---> vertex3
//
Vertex<Float,String> v = g1.lastVertex();
out.println( "adding vertex: vertex3" );
g1.addVertex( "vertex3" );
out.println( "adding edge: vertex2 -> 0.25 -> vertex3" );
g1.addEdge( v, g1.lastVertex(), 0.25f );
out.println( "graph is now:" );
out.println( g1 );
out.println();
assert g1.lastVertex().getValue() == "vertex3";
assert g1.size() == 3;
assert g1.countEdges() == 2;
assert g1.countVertices() == 3;
// + 1 vertex + 1 edge
//
// vertex1 --- 0.75 --> vertex2 --- 0.25 ---> vertex3
// |
// 0.1
// |
// \|/
// vertex4
//
out.println( "adding path: vertex2 -> 0.1 -> vertex4" );
g1.addPath( g1.getVertex( "vertex2" ), 0.1f, "vertex4" );
assert g1.countEdges() == 3;
assert g1.countVertices() == 4;
out.println( "graph is now:" );
out.println( g1 );
out.println();
}
@Test( dependsOnMethods = {"graphAdditionOfVerticesAndEdgesWithValues"} )
/** Simple listing of vertices/edges. */
public void graphListVerticesAndEdges()
{
assert g1.countEdges() == 3;
assert g1.countVertices() == 4;
// list vertices
Collection<String> vlist = g1.getAllVertexValues();
out.println( "vertices are: " + vlist );
assert vlist.size() == 4;
Collection<Float> elist = g1.getAllEdgeValues();
System.out.println( "edges are: " + elist );
assert elist.size() == 3;
//System.out.println( "leaves are: " + g.getLeaves() );
//System.out.println( "current root vertex is: " + g.getRootVertex() );
}
@Test( dependsOnMethods = {"graphListVerticesAndEdges"} )
/**
* circularises graph g1, to:
*<pre>
* ___ 0.02 ___
* / \
* vertex6 -- 0.98 vertex5
* \ | /
* 0.02 | 0.01
* \ | /
* vertex1 -- 0.75 -- vertex2 -- 0.25 -- vertex3
* |
* 0.1
* |
* vertex4
*</pre>
*/
public void graphCircularise()
{
assert g1.countEdges() == 3;
assert g1.countVertices() == 4;
out.println( "adding path: vertex2 -> 0.01 -> vertex5" );
g1.addPath( g1.getVertex( "vertex2" ), 0.01f, "vertex5" );
assert g1.countEdges() == 4;
assert g1.countVertices() == 5;
out.println( "adding path: vertex5 -> 0.02 -> vertex6" );
g1.addPath( g1.lastVertex(), 0.02f, "vertex6" );
assert g1.countEdges() == 5;
assert g1.countVertices() == 6;
out.println( "adding path: vertex6 -> 0.98 -> vertex2" );
g1.addEdge( g1.getVertex("vertex6"), g1.getVertex("vertex2"), 0.98f );
assert g1.countEdges() == 6;
assert g1.countVertices() == 6;
out.println( "adding loop: vertex6 -> 0.02 -> vertex2" );
g1.addEdge( g1.getVertex("vertex6"), g1.getVertex("vertex2"), 0.02f );
assert g1.countEdges() == 7;
assert g1.countVertices() == 6;
out.println( "graph is now:" );
out.println( g1 );
out.println();
for ( Vertex<Float,String> v : g1 )
{
List<Edge<Float,String>> inclist = v.getIncomingEdges();
out.println( "incoming edges of "
+ v
+ " == "
+ inclist.size()
+ ": "
+ inclist
);
List<Edge<Float,String>> outlist = v.getOutgoingEdges();
out.println( "outgoing edges of "
+ v
+ " == "
+ outlist.size()
+ ": "
+ outlist
);
}
}
@Test( dependsOnMethods = {"graphCircularise"} )
/**
* Tests behaviour of graph g1 as a {@link Set}: presence/absence of
* vertices in graph.
*/
public void graphContains()
{
assert g1.countEdges() == 7;
assert g1.countVertices() == 6;
boolean b = false;
out.println( "testing if graph contains each of its own vertices" );
for ( Vertex<Float,String> v : g1.getAllVertices() )
{
b = g1.contains( v );
out.println( "contains " + v + ": " + b );
assert b;
}
assert b : "didn't enter iteration loop!";
out.println();
b = false;
out.println( "testing if graph contains each of its own vertex values" );
for ( String s : g1.getAllVertexValues() )
{
b = g1.contains( s );
out.println( "contains vertex value '" + s + "': " + b );
assert b;
}
assert b : "didn't enter iteration loop!";
out.println();
b = true;
out.println( "testing if graph contains some random strings (these should all be false)" );
for ( String s : new String[] {"sdfsdf", "423234", "dhhdfg", "£$%%%^"} )
{
b = g1.contains( s );
out.println( "contains vertex value '" + s + "': " + b );
assert ! b;
}
assert ! b : "didn't enter iteration loop!";
}
@Test( dependsOnMethods = {"graphContains"} )
/** Tests removal of vertices. Adds a vertex to g1 then removes it. */
public void graphSubtraction()
{
out.println( "testing the removal of vertices" );
int ce = g1.countEdges();
int cv = g1.countVertices();
boolean b = false;
out.println();
out.println( "adding a temporary vertex" );
assert ! g1.contains( "temp" );
g1.addVertex("temp");
b = g1.contains( "temp" );
out.println("contains vertex 'temp'? " + b );
assert b;
g1.remove( "temp" );
b = g1.contains( "temp" );
out.println("contains vertex 'temp' post-removal? " + b );
assert ! b;
// check graph is exactly the same as when we started
assert g1.countEdges() == ce;
assert g1.countVertices() == cv;
}
@Test( dependsOnMethods = {"graphCircularise"} )
/**
* Tests depth-first traversal using circularised graph g1:
*<pre>
* ___ 0.02 ___
* / \
* vertex6 -- 0.98 vertex5
* \ | /
* 0.02 | 0.01
* \ | /
* vertex1 -- 0.75 -- vertex2 -- 0.25 -- vertex3
* |
* 0.1
* |
* vertex4
*</pre>
*/
public void graphTraversal()
{
//~~~ graph traversal ~~~
out.print( "depth-first order : " );
GraphIterator<Float,String> dfs = g1.traverseDepthFirst();
List<String> values = dfs.getValues();
out.println( join( ", ", values ) );
assert values.size() == g1.size();
out.print( "breadth-first order: " );
GraphIterator<Float,String> bfs = g1.traverseBreadthFirst();
values = bfs.getValues();
out.println( join( ", ", values ) );
out.println( "using stepwise iteration:" );
dfs.reset();
bfs.reset();
out.println("depth-first - breadth-first");
while ( dfs.hasNext() && bfs.hasNext() )
{
out.println( dfs.nextVertex()
+ " - "
+ bfs.nextVertex()
);
}
}
@Test( dependsOnMethods = {"graphCircularise"} )
/** Adds entire graph g1 to graph 2, and links them through vertices vertex1 & newvertex1. */
public void graphAddition()
{
//~~~ graph + graph operations ~~~
// record starting state
int ce = g1.countEdges();
int cv = g1.countVertices();
out.println();
out.println( "~~~ adding a graph to a graph ~~~" );
// g2:
//
// newvertex1 --- 1.0 --> newvertex2 --- 1.0 ---> newvertex3
// |
// 1.0
// |
// newvertex4
//
g2 = new Graph<Float,String>();
g2.addVertex( "newvertex1" );
g2.addPath( g2.lastVertex(), 1.0f, "newvertex2" );
g2.addPath( g2.lastVertex(), 1.0f, "newvertex3" );
g2.addPath( g2.getVertex("newvertex2"), 1.0f, "newvertex4" );
out.println("the graph to be added:");
out.println( g2 );
assert g2.countEdges() == 3;
assert g2.countVertices() == 4;
// add g1 to g2
g2.addGraph( g1 );
g2.addEdge( g1.getVertex("vertex1"), g2.getVertex("newvertex1") );
out.println("the added graph:");
out.println( g2 );
// check final state
assert g2.countEdges() == ce + 4
: "expected " + (ce+4) + " edges, found " + g1.countEdges();
assert g2.countVertices() == cv + 4
: "expected " + (cv+4) + " vertices, found " + g1.countVertices();
}
@Test( dependsOnMethods = {"graphAddition"} )
/** Clears graph g2 */
public void graphClear()
{
assert g2.countVertices() > 0;
out.println( "~~~ clearing a graph ~~~" );
g2.clear();
assert g2.countEdges() == 0;
assert g2.countVertices() == 0;
}
} // end class