/*
* Grapht, an open source dependency injector.
* Copyright 2014-2015 various contributors (see CONTRIBUTORS.txt)
* Copyright 2010-2014 Regents of the University of Minnesota
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.grouplens.grapht.graph;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Maps;
import org.junit.Test;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
/**
* @author <a href="http://www.grouplens.org">GroupLens Research</a>
*/
public class TestDAGNode {
@Test
public void testBasicLabel() {
DAGNode<String,String> node = DAGNode.singleton("foo");
assertThat(node, notNullValue());
assertThat(node.getLabel(), equalTo("foo"));
assertThat(node.getOutgoingEdges(), hasSize(0));
assertThat(node.getReachableNodes(),
contains(node));
assertThat(node.getOutgoingEdgeWithLabel("wombat"),
nullValue());
}
@Test
public void testSingleEdge() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNodeBuilder<String,String> bld = DAGNode.newBuilder("bar");
DAGNode<String,String> bar = bld.addEdge(foo, "wombat")
.build();
assertThat(bar.getLabel(), equalTo("bar"));
assertThat(bar.getOutgoingEdges(), hasSize(1));
DAGEdge<String,String> e = bar.getOutgoingEdges().iterator().next();
assertThat(e.getLabel(), equalTo("wombat"));
assertThat(e.getTail().getLabel(), equalTo("foo"));
assertThat(e.getTail().getOutgoingEdges(), hasSize(0));
assertThat(bar.getReachableNodes(),
containsInAnyOrder(foo, bar));
assertThat(bar.getSortedNodes(),
contains(foo, bar));
assertThat(bar.getOutgoingEdgeWithLabel("wombat").getTail(),
equalTo(foo));
}
@Test
public void testGetReverseEdge() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNodeBuilder<String,String> bld = DAGNode.newBuilder("bar");
bld.addEdge(foo, "wombat");
DAGNode<String,String> bar = bld.build();
assertThat(bar.getIncomingEdges(foo),
contains(DAGEdge.create(bar, foo, "wombat")));
}
@Test
public void testGetTwoReverseEdges() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNodeBuilder<String,String> bld = DAGNode.newBuilder("bar");
DAGNode<String,String> bar = bld.addEdge(foo, "wombat").build();
bld = DAGNode.newBuilder("blatz");
DAGNode<String,String> blatz = bld.addEdge(foo, "skunk").build();
bld = DAGNode.newBuilder("head");
DAGNode<String,String> head = bld.addEdge(bar, "wumpus")
.addEdge(blatz, "woozle")
.build();
assertThat(head.getOutgoingEdges(),
hasSize(2));
assertThat(head.getIncomingEdges(foo),
containsInAnyOrder(DAGEdge.create(bar, foo, "wombat"),
DAGEdge.create(blatz, foo, "skunk")));
assertThat(head.getReachableNodes(),
containsInAnyOrder(foo, bar, blatz, head));
}
@Test
public void testReplaceSingleNode() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.singleton("bar");
Map<DAGNode<String,String>,DAGNode<String,String>> mem = Maps.newHashMap();
DAGNode<String,String> replaced = foo.replaceNode(foo, bar, mem);
assertThat(replaced, equalTo(bar));
assertThat(mem, hasEntry(foo, bar));
}
@Test
public void testReplaceAbsentNode() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.singleton("bar");
DAGNode<String,String> blatz = DAGNode.singleton("blatz");
Map<DAGNode<String,String>,DAGNode<String,String>> mem = Maps.newHashMap();
DAGNode<String,String> replaced = foo.replaceNode(blatz, bar, mem);
assertThat(replaced, equalTo(foo));
assertThat(mem.size(), equalTo(0));
}
@Test
public void testReplaceEdgeNode() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.singleton("bar");
DAGNode<String,String> graph = DAGNode.<String,String>newBuilder("graph")
.addEdge(foo, "wombat")
.build();
Map<DAGNode<String,String>,DAGNode<String,String>> mem = Maps.newHashMap();
DAGNode<String,String> replaced = graph.replaceNode(foo, bar, mem);
assertThat(replaced, not(equalTo(graph)));
assertThat(mem, hasEntry(foo, bar));
assertThat(mem, hasEntry(graph, replaced));
assertThat(replaced.getAdjacentNodes(), contains(bar));
}
@Test
public void testReplaceDualUseNode() {
DAGNode<String,String> foo, fooP, bar, blatz, graph;
foo = DAGNode.singleton("foo");
// this node should be replaced once, not twice
fooP = DAGNode.<String,String>newBuilder("foo'")
.addEdge(foo, "-> foo")
.build();
bar = DAGNode.<String,String>newBuilder("bar")
.addEdge(fooP, "bar -> foo")
.build();
blatz = DAGNode.<String,String>newBuilder("blatz")
.addEdge(fooP, "blatz -> foo")
.build();
graph = DAGNode.<String,String>newBuilder("graph")
.addEdge(bar, "-> bar")
.addEdge(blatz, "-> blatz")
.build();
DAGNode<String,String> foo2 = DAGNode.singleton("foo2");
HashMap<DAGNode<String,String>,DAGNode<String,String>> memory = Maps.newHashMap();
DAGNode<String,String> replaced = graph.replaceNode(foo, foo2, memory);
assertThat(replaced, not(sameInstance(graph)));
// if we have > 5 nodes, then fooP was duplicated!
assertThat(replaced.getReachableNodes(),
hasSize(5));
assertThat(foo2, isIn(replaced.getReachableNodes()));
assertThat(foo, not(isIn(replaced.getReachableNodes())));
assertThat(fooP, not(isIn(replaced.getReachableNodes())));
assertThat(replaced.getSortedNodes().get(0),
equalTo(foo2));
assertThat(replaced.getSortedNodes().get(1).getLabel(),
equalTo("foo'"));
}
@Test
public void testTransformEdgeNoop() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> graph = DAGNode.<String,String>newBuilder("graph")
.addEdge(foo, "wombat")
.build();
DAGNode<String,String> g2 = graph.transformEdges((Function) Functions.constant(null));
assertThat(g2, sameInstance(graph));
}
@Test
public void testTransformEdgeRewrite() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> graph = DAGNode.<String,String>newBuilder("graph")
.addEdge(foo, "wombat")
.build();
DAGNode<String,String> g2 =
graph.transformEdges((Function) Functions.constant(DAGEdge.create(graph, foo,"hairball")));
assertThat(g2, not(sameInstance(graph)));
assertThat(g2.getOutgoingEdge(foo, "hairball"),
notNullValue());
}
@Test
public void testTransformDeeperEdge() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.singleton("bar");
DAGNode<String,String> wombat = DAGNode.<String,String>newBuilder("wombat")
.addEdge(foo, "wombat")
.build();
DAGNode<String,String> graph = DAGNode.<String,String>newBuilder("graph")
.addEdge(wombat, "wumpus")
.addEdge(bar, "woozle")
.build();
DAGNode<String,String> g2 =
graph.transformEdges(new Function<DAGEdge<String, String>, DAGEdge<String, String>>() {
@Nullable
@Override
public DAGEdge<String, String> apply(@Nullable DAGEdge<String, String> input) {
if (input != null && input.getLabel().equals("woozle")) {
return DAGEdge.create(input.getHead(), input.getTail(), "hatrack");
} else {
return null;
}
}
});
assertThat(g2, not(sameInstance(graph)));
assertThat(g2.getOutgoingEdge(bar, "hatrack"),
notNullValue());
assertThat(g2.getOutgoingEdge(bar, "woozle"),
nullValue());
assertThat(g2.getOutgoingEdge(wombat, "wumpus"),
notNullValue());
}
@Test
public void testFindBFSSingletonYes() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> needle = foo.findNodeBFS(Predicates.<DAGNode<String, String>>alwaysTrue());
assertThat(needle, sameInstance(foo));
}
@Test
public void testFindBFSSingletonNo() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> needle = foo.findNodeBFS(Predicates.<DAGNode<String, String>>alwaysFalse());
assertThat(needle, nullValue());
}
@Test
public void testFindBFSChildMatches() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.<String,String>newBuilder("bar")
.addEdge(foo, "foo")
.build();
DAGNode<String,String> needle =
bar.findNodeBFS(DAGNode.labelMatches(Predicates.equalTo("foo")));
assertThat(needle, sameInstance(foo));
}
@Test
public void testFindBFSFirstNode() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.<String,String>newBuilder("bar")
.addEdge(foo, "foo")
.build();
DAGNode<String,String> needle = bar.findNodeBFS(Predicates.<DAGNode<String, String>>alwaysTrue());
assertThat(needle, sameInstance(bar));
}
@Test
public void testFindBFSFirstFound() {
DAGNode<String,String> foo1 = DAGNode.singleton("foo");
DAGNode<String,String> foo2 = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.<String,String>newBuilder("bar")
.addEdge(foo1, "hello")
.build();
DAGNode<String,String> bam = DAGNode.<String,String>newBuilder("bam")
.addEdge(bar, "wombat")
.addEdge(foo2, "goodbye")
.build();
DAGNode<String,String> needle = bam.findNodeBFS(DAGNode.labelMatches(Predicates.equalTo("foo")));
assertThat(needle, sameInstance(foo2));
}
@Test
public void testEdgeBFSSingleYes() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.<String,String>newBuilder("bar")
.addEdge(foo, "-> foo")
.build();
DAGEdge<String,String> edge = bar.findEdgeBFS(Predicates.alwaysTrue());
// we should have just found the only edge
assertThat(edge, isIn(bar.getOutgoingEdges()));
}
@Test
public void testEdgeBFSSingleNo() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.<String,String>newBuilder("bar")
.addEdge(foo, "-> foo")
.build();
DAGEdge<String,String> edge = bar.findEdgeBFS(Predicates.alwaysFalse());
// no edge to find
assertThat(edge, nullValue());
}
@Test
public void testEdgeBFSByName() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> baz = DAGNode.singleton("baz");
DAGNode<String,String> bar = DAGNode.<String,String>newBuilder("bar")
.addEdge(foo, "-> foo")
.addEdge(baz, "-> baz")
.build();
Predicate<DAGEdge<?, String>> pred = DAGEdge.labelMatches(Predicates.equalTo("-> baz"));
DAGEdge<String,String> edge = bar.findEdgeBFS(pred);
// we should find the correct edge
assertThat(edge, isIn(bar.getOutgoingEdges()));
assertThat(edge.getTail(), equalTo(baz));
assertThat(edge.getLabel(), equalTo("-> baz"));
}
@Test
public void testEdgeBFSFirst() {
DAGNode<String,String> foo = DAGNode.singleton("foo");
DAGNode<String,String> bar = DAGNode.<String,String>newBuilder("bar")
.addEdge(foo, "hello")
.build();
DAGNode<String,String> bam = DAGNode.<String,String>newBuilder("bam")
.addEdge(bar, "wombat")
.addEdge(foo, "goodbye")
.build();
DAGEdge<String,String> edge = bam.findEdgeBFS(DAGEdge.tailMatches(Predicates.equalTo(foo)));
// we should find the first edge
assertThat(edge.getLabel(),
equalTo("goodbye"));
}
}