/*
* 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 tree used (object member {@link #tree}) in this class is:
*<pre>
* F
* \
* E -- C
* / \
* G B -- A
* /
* H -- D
*
*</pre>
*<h2>depth-first traversal</h2>
*<p>
* If the starting vertex was A, the returned list in an unsorted DF
* traversal should be one of:
*<ol>
* <li>A, B, C, E, F, G, D, H</li>
* <li>A, B, D, H, C, E, F, G</li>
* <li>A, B, D, H, C, E, G, F</li>
* <li>A, B, C, E, G, F, D, H</li>
*</ol>
*</p>
*/
@Test( groups="util.graphs", sequential=true, timeOut=5000 )
public class GraphVisitorTest
{
protected Graph<Integer,Character> tree = new Graph<Integer,Character>();
@BeforeTest
public void setupLogging()
{
Logger.getLogger("org.eurocarbdb.util.graph").setLevel( Level.ALL );
}
@Test
public void graphInitialConstruction()
{
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 );
}
@Test( dependsOnMethods = {"graphInitialConstruction"} )
public void graphDepthFirstTraversalSmokeTest()
{
DepthFirstGraphVisitor<Integer,Character> v1
= new DepthFirstGraphVisitor<Integer,Character>();
v1.visit( tree );
}
@Test( dependsOnMethods = {"graphInitialConstruction"} )
public void graphDepthFirstTraversal()
{
DepthFirstGraphVisitor<Integer,Character> v2
= new DepthFirstGraphVisitor<Integer,Character>()
{
int depth = 0;
public void accept( Vertex<Integer,Character> v )
{
depth++;
for ( int i = 1; i < depth; i++ ) out.print(" ");
out.println( "> approaching vertex " + v.getValue() );
super.accept( v );
for ( int i = 1; i < depth; i++ ) out.print(" ");
out.println( "< leaving vertex " + v.getValue() );
depth--;
}
};
v2.visit( tree );
}
/**
* This tests that a (unsorted) depth-traversal traversal proceeds
* in a correct order.
*/
@Test( dependsOnMethods = {"graphInitialConstruction"} )
public void graphDepthFirstTraversalOrderIsCorrect()
{
final char[] correct_order1 = {'A', 'B', 'C', 'E', 'F', 'G', 'D', 'H' };
final char[] correct_order2 = {'A', 'B', 'C', 'E', 'G', 'F', 'D', 'H' };
final char[] correct_order3 = {'A', 'B', 'D', 'H', 'C', 'E', 'F', 'G' };
final char[] correct_order4 = {'A', 'B', 'D', 'H', 'C', 'E', 'G', 'F' };
final char[] observed_order = new char[ correct_order1.length ];
DepthFirstGraphVisitor<Integer,Character> v3
= new DepthFirstGraphVisitor<Integer,Character>()
{
int index = 0;
public void accept( Vertex<Integer,Character> v )
{
char value = v.getValue();
observed_order[index] = value;
index++;
super.accept( v );
}
};
v3.visit( tree );
out.println("expecting one of the following:");
out.println( correct_order1 );
out.println( correct_order2 );
out.println( correct_order3 );
out.println( correct_order4 );
out.println();
out.println("observed:");
out.println( observed_order );
assert Arrays.equals( correct_order1, observed_order )
|| Arrays.equals( correct_order2, observed_order )
|| Arrays.equals( correct_order3, observed_order )
|| Arrays.equals( correct_order4, observed_order )
: "order of vertices in depth-first traversal was incorrect"
;
out.println();
out.println("depth-first order is correct");
}
private 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;
}
} // end class