tom

Added more unit tests for the graph utilities.

...@@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
15 * @param <V> vertex type 15 * @param <V> vertex type
16 * @param <E> edge type 16 * @param <E> edge type
17 */ 17 */
18 -public abstract class AbstractPathSearch<V extends Vertex, E extends Edge<V>> 18 +public abstract class AbstractGraphPathSearch<V extends Vertex, E extends Edge<V>>
19 implements GraphPathSearch<V, E> { 19 implements GraphPathSearch<V, E> {
20 20
21 private double samenessThreshold = 0.000000001; 21 private double samenessThreshold = 0.000000001;
......
1 +package org.onlab.graph;
2 +
3 +import java.util.HashSet;
4 +import java.util.Set;
5 +
6 +/**
7 + * Implementation of the BFS algorithm.
8 + */
9 +public class BreadthFirstSearch<V extends Vertex, E extends Edge<V>>
10 + extends AbstractGraphPathSearch<V, E> {
11 +
12 + @Override
13 + public Result<V, E> search(Graph<V, E> graph, V src, V dst, EdgeWeight<V, E> ew) {
14 + checkArguments(graph, src, dst);
15 +
16 + // Prepare the graph result.
17 + DefaultResult result = new DefaultResult(src, dst);
18 +
19 + // Setup the starting frontier with the source as the sole vertex.
20 + Set<V> frontier = new HashSet<>();
21 + result.costs.put(src, 0.0);
22 + frontier.add(src);
23 +
24 + search: while (!frontier.isEmpty()) {
25 + // Prepare the next frontier.
26 + Set<V> next = new HashSet<>();
27 +
28 + // Visit all vertexes in the current frontier.
29 + for (V vertex : frontier) {
30 + double cost = result.cost(vertex);
31 +
32 + // Visit all egress edges of the current frontier vertex.
33 + for (E edge : graph.getEdgesFrom(vertex)) {
34 + V nextVertex = edge.dst();
35 + if (!result.hasCost(nextVertex)) {
36 + // If this vertex has not been visited yet, update it.
37 + result.updateVertex(nextVertex, edge,
38 + cost + (ew == null ? 1.0 : ew.weight(edge)),
39 + true);
40 + // If we have reached our intended destination, bail.
41 + if (nextVertex.equals(dst))
42 + break search;
43 + next.add(nextVertex);
44 + }
45 + }
46 + }
47 +
48 + // Promote the next frontier.
49 + frontier = next;
50 + }
51 +
52 + // Finally, but the paths on the search result and return.
53 + result.buildPaths();
54 + return result;
55 + }
56 +
57 +}
...@@ -14,8 +14,6 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -14,8 +14,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
14 */ 14 */
15 public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements MutablePath<V, E> { 15 public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements MutablePath<V, E> {
16 16
17 - private V src = null;
18 - private V dst = null;
19 private final List<E> edges = new ArrayList<>(); 17 private final List<E> edges = new ArrayList<>();
20 private double cost = 0.0; 18 private double cost = 0.0;
21 19
...@@ -32,20 +30,18 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements ...@@ -32,20 +30,18 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements
32 */ 30 */
33 public DefaultMutablePath(Path<V, E> path) { 31 public DefaultMutablePath(Path<V, E> path) {
34 checkNotNull(path, "Path cannot be null"); 32 checkNotNull(path, "Path cannot be null");
35 - this.src = path.src();
36 - this.dst = path.dst();
37 this.cost = path.cost(); 33 this.cost = path.cost();
38 edges.addAll(path.edges()); 34 edges.addAll(path.edges());
39 } 35 }
40 36
41 @Override 37 @Override
42 public V src() { 38 public V src() {
43 - return src; 39 + return edges.isEmpty() ? null : edges.get(0).src();
44 } 40 }
45 41
46 @Override 42 @Override
47 public V dst() { 43 public V dst() {
48 - return dst; 44 + return edges.isEmpty() ? null : edges.get(edges.size() - 1).dst();
49 } 45 }
50 46
51 @Override 47 @Override
...@@ -69,28 +65,35 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements ...@@ -69,28 +65,35 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements
69 } 65 }
70 66
71 @Override 67 @Override
68 + public void insertEdge(E edge) {
69 + checkNotNull(edge, "Edge cannot be null");
70 + checkArgument(edges.isEmpty() || src().equals(edge.dst()),
71 + "Edge destination must be the same as the current path source");
72 + edges.add(0, edge);
73 + }
74 +
75 + @Override
72 public void appendEdge(E edge) { 76 public void appendEdge(E edge) {
73 checkNotNull(edge, "Edge cannot be null"); 77 checkNotNull(edge, "Edge cannot be null");
74 - checkArgument(edges.isEmpty() || dst.equals(edge.src()), 78 + checkArgument(edges.isEmpty() || dst().equals(edge.src()),
75 "Edge source must be the same as the current path destination"); 79 "Edge source must be the same as the current path destination");
76 - dst = edge.dst();
77 edges.add(edge); 80 edges.add(edge);
78 } 81 }
79 82
80 @Override 83 @Override
81 - public void insertEdge(E edge) { 84 + public void removeEdge(E edge) {
82 - checkNotNull(edge, "Edge cannot be null"); 85 + checkArgument(edge.src().equals(edge.dst()) ||
83 - checkArgument(edges.isEmpty() || src.equals(edge.dst()), 86 + edges.indexOf(edge) == 0 ||
84 - "Edge destination must be the same as the current path source"); 87 + edges.lastIndexOf(edge) == edges.size() - 1,
85 - src = edge.src(); 88 + "Edge must be at start or end of path, or it must be a cyclic edge");
86 - edges.add(0, edge); 89 + edges.remove(edge);
87 } 90 }
88 91
89 @Override 92 @Override
90 public String toString() { 93 public String toString() {
91 return com.google.common.base.Objects.toStringHelper(this) 94 return com.google.common.base.Objects.toStringHelper(this)
92 - .add("src", src) 95 + .add("src", src())
93 - .add("dst", dst) 96 + .add("dst", dst())
94 .add("cost", cost) 97 .add("cost", cost)
95 .add("edges", edges) 98 .add("edges", edges)
96 .toString(); 99 .toString();
...@@ -98,19 +101,17 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements ...@@ -98,19 +101,17 @@ public class DefaultMutablePath<V extends Vertex, E extends Edge<V>> implements
98 101
99 @Override 102 @Override
100 public int hashCode() { 103 public int hashCode() {
101 - return Objects.hash(src, dst, edges, cost); 104 + return Objects.hash(edges, cost);
102 } 105 }
103 106
104 @Override 107 @Override
105 public boolean equals(Object obj) { 108 public boolean equals(Object obj) {
106 if (obj instanceof DefaultMutablePath) { 109 if (obj instanceof DefaultMutablePath) {
107 final DefaultMutablePath other = (DefaultMutablePath) obj; 110 final DefaultMutablePath other = (DefaultMutablePath) obj;
108 - return super.equals(obj) && 111 + return Objects.equals(this.cost, other.cost) &&
109 - Objects.equals(this.src, other.src) &&
110 - Objects.equals(this.dst, other.dst) &&
111 - Objects.equals(this.cost, other.cost) &&
112 Objects.equals(this.edges, other.edges); 112 Objects.equals(this.edges, other.edges);
113 } 113 }
114 return false; 114 return false;
115 } 115 }
116 +
116 } 117 }
......
...@@ -73,8 +73,7 @@ public class DefaultPath<V extends Vertex, E extends Edge<V>> implements Path<V, ...@@ -73,8 +73,7 @@ public class DefaultPath<V extends Vertex, E extends Edge<V>> implements Path<V,
73 public boolean equals(Object obj) { 73 public boolean equals(Object obj) {
74 if (obj instanceof DefaultPath) { 74 if (obj instanceof DefaultPath) {
75 final DefaultPath other = (DefaultPath) obj; 75 final DefaultPath other = (DefaultPath) obj;
76 - return super.equals(obj) && 76 + return Objects.equals(this.src, other.src) &&
77 - Objects.equals(this.src, other.src) &&
78 Objects.equals(this.dst, other.dst) && 77 Objects.equals(this.dst, other.dst) &&
79 Objects.equals(this.cost, other.cost) && 78 Objects.equals(this.cost, other.cost) &&
80 Objects.equals(this.edges, other.edges); 79 Objects.equals(this.edges, other.edges);
......
...@@ -9,7 +9,7 @@ import java.util.Set; ...@@ -9,7 +9,7 @@ import java.util.Set;
9 * one, but all shortest paths between the source and destinations. 9 * one, but all shortest paths between the source and destinations.
10 */ 10 */
11 public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>> 11 public class DijkstraGraphSearch<V extends Vertex, E extends Edge<V>>
12 - extends AbstractPathSearch<V, E> { 12 + extends AbstractGraphPathSearch<V, E> {
13 13
14 @Override 14 @Override
15 public Result<V, E> search(Graph<V, E> g, V src, V dst, EdgeWeight<V, E> ew) { 15 public Result<V, E> search(Graph<V, E> g, V src, V dst, EdgeWeight<V, E> ew) {
......
...@@ -22,6 +22,15 @@ public interface MutablePath<V extends Vertex, E extends Edge<V>> extends Path<V ...@@ -22,6 +22,15 @@ public interface MutablePath<V extends Vertex, E extends Edge<V>> extends Path<V
22 void appendEdge(E edge); 22 void appendEdge(E edge);
23 23
24 /** 24 /**
25 + * Removes the specified edge. This edge must be either at the start or
26 + * at the end of the path, or it must be a cyclic edge in order not to
27 + * violate the contiguous path property.
28 + *
29 + * @param edge edge to be removed
30 + */
31 + void removeEdge(E edge);
32 +
33 + /**
25 * Sets the total path cost as a unit-less double. 34 * Sets the total path cost as a unit-less double.
26 * 35 *
27 * @param cost new path cost 36 * @param cost new path cost
......
1 package org.onlab.graph; 1 package org.onlab.graph;
2 2
3 -import com.google.common.collect.ImmutableSet;
4 import org.junit.Test; 3 import org.junit.Test;
5 4
5 +import static com.google.common.collect.ImmutableSet.of;
6 +import static org.junit.Assert.assertEquals;
7 +
6 /** 8 /**
7 * Base for all graph search tests. 9 * Base for all graph search tests.
8 */ 10 */
9 -public abstract class AbstractGraphSearchTest extends GraphTest { 11 +public abstract class AbstractGraphPathSearchTest extends GraphTest {
10 12
11 /** 13 /**
12 - * Creates a graph search to be tested. 14 + * Creates a test-specific graph search to exercise.
13 * 15 *
14 * @return graph search 16 * @return graph search
15 */ 17 */
16 - protected abstract GraphPathSearch<TestVertex, TestEdge> graphSearch(); 18 + protected abstract AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch();
17 19
18 @Test(expected = IllegalArgumentException.class) 20 @Test(expected = IllegalArgumentException.class)
19 - public void badSource() { 21 + public void noSuchSourceArgument() {
20 - graphSearch().search(new AdjacencyListsGraph<>(ImmutableSet.of(B, C), 22 + graphSearch().search(new AdjacencyListsGraph<>(of(B, C),
21 - ImmutableSet.of(new TestEdge(B, C, 1))), 23 + of(new TestEdge(B, C, 1))),
22 A, H, weight); 24 A, H, weight);
23 } 25 }
24 26
25 @Test(expected = NullPointerException.class) 27 @Test(expected = NullPointerException.class)
26 - public void nullSource() { 28 + public void nullGraphArgument() {
27 - graphSearch().search(new AdjacencyListsGraph<>(ImmutableSet.of(B, C), 29 + graphSearch().search(null, A, H, weight);
28 - ImmutableSet.of(new TestEdge(B, C, 1))),
29 - null, H, weight);
30 } 30 }
31 31
32 @Test(expected = NullPointerException.class) 32 @Test(expected = NullPointerException.class)
33 - public void nullGraph() { 33 + public void nullSourceArgument() {
34 - graphSearch().search(null, A, H, weight); 34 + graphSearch().search(new AdjacencyListsGraph<>(of(B, C),
35 + of(new TestEdge(B, C, 1))),
36 + null, H, weight);
37 + }
38 +
39 + @Test
40 + public void samenessThreshold() {
41 + AbstractGraphPathSearch<TestVertex, TestEdge> search = graphSearch();
42 + search.setSamenessThreshold(0.3);
43 + assertEquals("incorrect threshold", 0.3, search.samenessThreshold(), 0.01);
35 } 44 }
36 45
37 } 46 }
......
...@@ -22,22 +22,9 @@ public class AdjacencyListsGraphTest { ...@@ -22,22 +22,9 @@ public class AdjacencyListsGraphTest {
22 private static final TestVertex G = new TestVertex("G"); 22 private static final TestVertex G = new TestVertex("G");
23 23
24 private final Set<TestEdge> edges = 24 private final Set<TestEdge> edges =
25 - ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(A, C, 1), 25 + ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(B, C, 1),
26 - new TestEdge(B, C, 1), new TestEdge(C, D, 1), 26 + new TestEdge(C, D, 1), new TestEdge(D, A, 1),
27 - new TestEdge(D, A, 1)); 27 + new TestEdge(B, D, 1));
28 -
29 - @Test
30 - public void basics() {
31 - Set<TestVertex> vertexes = ImmutableSet.of(A, B, C, D, E, F);
32 - AdjacencyListsGraph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(vertexes, edges);
33 - assertEquals("incorrect vertex count", 6, graph.getVertexes().size());
34 - assertEquals("incorrect edge count", 5, graph.getEdges().size());
35 -
36 - assertEquals("incorrect egress edge count", 2, graph.getEdgesFrom(A).size());
37 - assertEquals("incorrect ingress edge count", 1, graph.getEdgesTo(A).size());
38 - assertEquals("incorrect ingress edge count", 2, graph.getEdgesTo(C).size());
39 - assertEquals("incorrect egress edge count", 1, graph.getEdgesFrom(C).size());
40 - }
41 28
42 @Test 29 @Test
43 public void equality() { 30 public void equality() {
...@@ -53,4 +40,18 @@ public class AdjacencyListsGraphTest { ...@@ -53,4 +40,18 @@ public class AdjacencyListsGraphTest {
53 .addEqualityGroup(different) 40 .addEqualityGroup(different)
54 .testEquals(); 41 .testEquals();
55 } 42 }
43 +
44 + @Test
45 + public void basics() {
46 + Set<TestVertex> vertexes = ImmutableSet.of(A, B, C, D, E, F);
47 + AdjacencyListsGraph<TestVertex, TestEdge> graph = new AdjacencyListsGraph<>(vertexes, edges);
48 + assertEquals("incorrect vertex count", 6, graph.getVertexes().size());
49 + assertEquals("incorrect edge count", 5, graph.getEdges().size());
50 +
51 + assertEquals("incorrect egress edge count", 1, graph.getEdgesFrom(A).size());
52 + assertEquals("incorrect ingress edge count", 1, graph.getEdgesTo(A).size());
53 + assertEquals("incorrect ingress edge count", 1, graph.getEdgesTo(C).size());
54 + assertEquals("incorrect egress edge count", 2, graph.getEdgesFrom(B).size());
55 + assertEquals("incorrect ingress edge count", 2, graph.getEdgesTo(D).size());
56 + }
56 } 57 }
......
...@@ -7,27 +7,28 @@ import java.util.Set; ...@@ -7,27 +7,28 @@ import java.util.Set;
7 import static org.junit.Assert.assertEquals; 7 import static org.junit.Assert.assertEquals;
8 8
9 /** 9 /**
10 - * Test of the BFS algorithm. 10 + * Test of the BFS and similar path search algorithms.
11 */ 11 */
12 -public abstract class BreadthFirstSearchTest extends AbstractGraphSearchTest { 12 +public class BreadthFirstSearchTest extends AbstractGraphPathSearchTest {
13 13
14 @Override 14 @Override
15 - protected GraphPathSearch<TestVertex, TestEdge> graphSearch() { 15 + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() {
16 - return null; // new BreadthFirstSearch(); 16 + return new BreadthFirstSearch<>();
17 } 17 }
18 18
19 @Test 19 @Test
20 - public void basics() { 20 + public void defaultGraphTest() {
21 - runBasics(3, 8.0, 7); 21 + executeDefaultTest(7, 3, 8.0);
22 } 22 }
23 23
24 @Test 24 @Test
25 - public void defaultWeight() { 25 + public void defaultHopCountWeight() {
26 weight = null; 26 weight = null;
27 - runBasics(3, 3.0, 7); 27 + executeDefaultTest(7, 3, 3.0);
28 } 28 }
29 29
30 - protected void runBasics(int expectedLength, double expectedCost, int expectedPaths) { 30 + // Executes the default test
31 + protected void executeDefaultTest(int pathCount, int pathLength, double pathCost) {
31 g = new AdjacencyListsGraph<>(vertices(), edges()); 32 g = new AdjacencyListsGraph<>(vertices(), edges());
32 33
33 GraphPathSearch<TestVertex, TestEdge> search = graphSearch(); 34 GraphPathSearch<TestVertex, TestEdge> search = graphSearch();
...@@ -37,12 +38,29 @@ public abstract class BreadthFirstSearchTest extends AbstractGraphSearchTest { ...@@ -37,12 +38,29 @@ public abstract class BreadthFirstSearchTest extends AbstractGraphSearchTest {
37 Path p = paths.iterator().next(); 38 Path p = paths.iterator().next();
38 assertEquals("incorrect src", A, p.src()); 39 assertEquals("incorrect src", A, p.src());
39 assertEquals("incorrect dst", H, p.dst()); 40 assertEquals("incorrect dst", H, p.dst());
40 - assertEquals("incorrect path length", expectedLength, p.edges().size()); 41 + assertEquals("incorrect path length", pathLength, p.edges().size());
41 - assertEquals("incorrect path cost", expectedCost, p.cost(), 0.1); 42 + assertEquals("incorrect path cost", pathCost, p.cost(), 0.1);
42 43
43 paths = search.search(g, A, null, weight).paths(); 44 paths = search.search(g, A, null, weight).paths();
44 printPaths(paths); 45 printPaths(paths);
45 - assertEquals("incorrect paths count", expectedPaths, paths.size()); 46 + assertEquals("incorrect paths count", pathCount, paths.size());
47 + }
48 +
49 + // Executes the search and validates its results.
50 + protected void executeSearch(GraphPathSearch<TestVertex, TestEdge> search,
51 + Graph<TestVertex, TestEdge> graph,
52 + TestVertex src, TestVertex dst,
53 + EdgeWeight<TestVertex, TestEdge> weight,
54 + int pathCount, double pathCost) {
55 + GraphPathSearch.Result<TestVertex, TestEdge> result =
56 + search.search(graph, src, dst, weight);
57 + Set<Path<TestVertex, TestEdge>> paths = result.paths();
58 + printPaths(paths);
59 + assertEquals("incorrect paths count", pathCount, paths.size());
60 + if (pathCount > 0) {
61 + Path<TestVertex, TestEdge> path = paths.iterator().next();
62 + assertEquals("incorrect path cost", pathCost, path.cost(), 0.1);
63 + }
46 } 64 }
47 65
48 } 66 }
......
1 +package org.onlab.graph;
2 +
3 +import com.google.common.collect.ImmutableList;
4 +import com.google.common.testing.EqualsTester;
5 +import org.junit.Test;
6 +
7 +import java.util.Iterator;
8 +import java.util.List;
9 +
10 +import static com.google.common.collect.ImmutableList.of;
11 +import static org.junit.Assert.assertEquals;
12 +import static org.junit.Assert.assertNull;
13 +
14 +/**
15 + * Test of the default mutable path.
16 + */
17 +public class DefaultMutablePathTest extends DefaultPathTest {
18 +
19 + @Test
20 + public void equality() {
21 + DefaultPath<TestVertex, TestEdge> p1 =
22 + new DefaultPath<>(of(new TestEdge(A, B, 1),
23 + new TestEdge(B, C, 1)), 2.0);
24 + DefaultPath<TestVertex, TestEdge> p2 =
25 + new DefaultPath<>(of(new TestEdge(A, B, 1),
26 + new TestEdge(B, D, 1)), 2.0);
27 + new EqualsTester().addEqualityGroup(new DefaultMutablePath<>(p1),
28 + new DefaultMutablePath<>(p1))
29 + .addEqualityGroup(new DefaultMutablePath<>(p2))
30 + .testEquals();
31 + }
32 +
33 + @Test
34 + public void empty() {
35 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
36 + assertNull("src should be null", p.src());
37 + assertNull("dst should be null", p.dst());
38 + assertEquals("incorrect edge count", 0, p.edges().size());
39 + assertEquals("incorrect path cost", 0.0, p.cost(), 0.1);
40 + }
41 +
42 + @Test
43 + public void pathCost() {
44 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
45 + p.setCost(4);
46 + assertEquals("incorrect path cost", 4.0, p.cost(), 0.1);
47 + }
48 +
49 + private void validatePath(Path<TestVertex, TestEdge> p,
50 + TestVertex src, TestVertex dst, int length) {
51 + validatePath(p, src, dst, length, 0.0);
52 + }
53 +
54 + @Test
55 + public void insertEdge() {
56 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
57 + p.insertEdge(new TestEdge(B, C, 1));
58 + p.insertEdge(new TestEdge(A, B, 1));
59 + validatePath(p, A, C, 2);
60 + }
61 +
62 + @Test
63 + public void appendEdge() {
64 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
65 + p.appendEdge(new TestEdge(A, B, 1));
66 + p.appendEdge(new TestEdge(B, C, 1));
67 + validatePath(p, A, C, 2);
68 + }
69 +
70 + @Test
71 + public void removeEdge() {
72 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
73 + p.appendEdge(new TestEdge(A, B, 1));
74 + p.appendEdge(new TestEdge(B, C, 1));
75 + p.appendEdge(new TestEdge(C, C, 2));
76 + p.appendEdge(new TestEdge(C, D, 1));
77 + validatePath(p, A, D, 4);
78 +
79 + p.removeEdge(new TestEdge(A, B, 1));
80 + validatePath(p, B, D, 3);
81 +
82 + p.removeEdge(new TestEdge(C, C, 2));
83 + validatePath(p, B, D, 2);
84 +
85 + p.removeEdge(new TestEdge(C, D, 1));
86 + validatePath(p, B, C, 1);
87 + }
88 +
89 + @Test
90 + public void toImmutable() {
91 + MutablePath<TestVertex, TestEdge> p = new DefaultMutablePath<>();
92 + p.appendEdge(new TestEdge(A, B, 1));
93 + p.appendEdge(new TestEdge(B, C, 1));
94 + validatePath(p, A, C, 2);
95 +
96 + assertEquals("immutables should equal", p.toImmutable(), p.toImmutable());
97 + validatePath(p.toImmutable(), A, C, 2);
98 + }
99 +}
1 +package org.onlab.graph;
2 +
3 +import com.google.common.collect.ImmutableList;
4 +import com.google.common.testing.EqualsTester;
5 +import org.junit.Test;
6 +
7 +import java.util.List;
8 +
9 +import static com.google.common.collect.ImmutableList.of;
10 +import static org.junit.Assert.assertEquals;
11 +import static org.junit.Assert.assertNull;
12 +
13 +/**
14 + * Test of the default path.
15 + */
16 +public class DefaultPathTest extends GraphTest {
17 +
18 + @Test
19 + public void equality() {
20 + List<TestEdge> edges = of(new TestEdge(A, B, 1), new TestEdge(B, C, 1));
21 + new EqualsTester().addEqualityGroup(new DefaultPath<>(edges, 2.0),
22 + new DefaultPath<>(edges, 2.0))
23 + .addEqualityGroup(new DefaultPath<>(edges, 3.0))
24 + .testEquals();
25 + }
26 +
27 + @Test
28 + public void basics() {
29 + Path<TestVertex, TestEdge> p = new DefaultPath<>(of(new TestEdge(A, B, 1),
30 + new TestEdge(B, C, 1)), 2.0);
31 + validatePath(p, A, C, 2, 2.0);
32 + }
33 +
34 + // Validates the path against expected attributes
35 + protected void validatePath(Path<TestVertex, TestEdge> p,
36 + TestVertex src, TestVertex dst,
37 + int length, double cost) {
38 + assertEquals("incorrect path length", length, p.edges().size());
39 + assertEquals("incorrect source", src, p.src());
40 + assertEquals("incorrect destination", dst, p.dst());
41 + assertEquals("incorrect path cost", cost, p.cost(), 0.1);
42 + }
43 +
44 +}
1 package org.onlab.graph; 1 package org.onlab.graph;
2 2
3 -import com.google.common.collect.ImmutableSet;
4 import org.junit.Test; 3 import org.junit.Test;
5 4
6 import java.util.Set; 5 import java.util.Set;
7 6
7 +import static com.google.common.collect.ImmutableSet.of;
8 import static org.junit.Assert.assertEquals; 8 import static org.junit.Assert.assertEquals;
9 9
10 /** 10 /**
...@@ -13,30 +13,30 @@ import static org.junit.Assert.assertEquals; ...@@ -13,30 +13,30 @@ import static org.junit.Assert.assertEquals;
13 public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { 13 public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
14 14
15 @Override 15 @Override
16 - protected GraphPathSearch<TestVertex, TestEdge> graphSearch() { 16 + protected AbstractGraphPathSearch<TestVertex, TestEdge> graphSearch() {
17 return new DijkstraGraphSearch<>(); 17 return new DijkstraGraphSearch<>();
18 } 18 }
19 19
20 @Test 20 @Test
21 @Override 21 @Override
22 - public void basics() { 22 + public void defaultGraphTest() {
23 - runBasics(5, 5.0, 7); 23 + executeDefaultTest(7, 5, 5.0);
24 } 24 }
25 25
26 @Test 26 @Test
27 - public void defaultWeight() { 27 + @Override
28 + public void defaultHopCountWeight() {
28 weight = null; 29 weight = null;
29 - runBasics(3, 3.0, 10); 30 + executeDefaultTest(10, 3, 3.0);
30 } 31 }
31 32
32 @Test 33 @Test
33 public void noPath() { 34 public void noPath() {
34 - g = new AdjacencyListsGraph<>(ImmutableSet.of(A, B, C, D), 35 + g = new AdjacencyListsGraph<>(of(A, B, C, D),
35 - ImmutableSet.of(new TestEdge(A, B, 1), 36 + of(new TestEdge(A, B, 1),
36 new TestEdge(B, A, 1), 37 new TestEdge(B, A, 1),
37 new TestEdge(C, D, 1), 38 new TestEdge(C, D, 1),
38 new TestEdge(D, C, 1))); 39 new TestEdge(D, C, 1)));
39 -
40 GraphPathSearch<TestVertex, TestEdge> gs = graphSearch(); 40 GraphPathSearch<TestVertex, TestEdge> gs = graphSearch();
41 Set<Path<TestVertex, TestEdge>> paths = gs.search(g, A, B, weight).paths(); 41 Set<Path<TestVertex, TestEdge>> paths = gs.search(g, A, B, weight).paths();
42 printPaths(paths); 42 printPaths(paths);
...@@ -54,24 +54,19 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { ...@@ -54,24 +54,19 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
54 } 54 }
55 55
56 @Test 56 @Test
57 - public void multiPath1() { 57 + public void simpleMultiplePath() {
58 - g = new AdjacencyListsGraph<>(ImmutableSet.of(A, B, C, D), 58 + g = new AdjacencyListsGraph<>(of(A, B, C, D),
59 - ImmutableSet.of(new TestEdge(A, B, 1), 59 + of(new TestEdge(A, B, 1),
60 new TestEdge(A, C, 1), 60 new TestEdge(A, C, 1),
61 new TestEdge(B, D, 1), 61 new TestEdge(B, D, 1),
62 new TestEdge(C, D, 1))); 62 new TestEdge(C, D, 1)));
63 - 63 + executeSearch(graphSearch(), g, A, D, weight, 2, 2.0);
64 - GraphPathSearch<TestVertex, TestEdge> gs = graphSearch();
65 - Set<Path<TestVertex, TestEdge>> paths = gs.search(g, A, D, weight).paths();
66 - printPaths(paths);
67 - assertEquals("incorrect paths count", 2, paths.size());
68 - assertEquals("incorrect path cost", 2.0, paths.iterator().next().cost(), 0.1);
69 } 64 }
70 65
71 @Test 66 @Test
72 - public void multiPath2() { 67 + public void denseMultiplePath() {
73 - g = new AdjacencyListsGraph<>(ImmutableSet.of(A, B, C, D, E, F, G), 68 + g = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G),
74 - ImmutableSet.of(new TestEdge(A, B, 1), 69 + of(new TestEdge(A, B, 1),
75 new TestEdge(A, C, 1), 70 new TestEdge(A, C, 1),
76 new TestEdge(B, D, 1), 71 new TestEdge(B, D, 1),
77 new TestEdge(C, D, 1), 72 new TestEdge(C, D, 1),
...@@ -80,31 +75,20 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { ...@@ -80,31 +75,20 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest {
80 new TestEdge(E, G, 1), 75 new TestEdge(E, G, 1),
81 new TestEdge(F, G, 1), 76 new TestEdge(F, G, 1),
82 new TestEdge(A, G, 4))); 77 new TestEdge(A, G, 4)));
83 - 78 + executeSearch(graphSearch(), g, A, G, weight, 5, 4.0);
84 - GraphPathSearch<TestVertex, TestEdge> gs = graphSearch();
85 - GraphPathSearch.Result<TestVertex, TestEdge> gsr = gs.search(g, A, G, weight);
86 - Set<Path<TestVertex, TestEdge>> paths = gsr.paths();
87 - printPaths(paths);
88 - assertEquals("incorrect paths count", 5, paths.size());
89 - assertEquals("incorrect path cost", 4.0, paths.iterator().next().cost(), 0.1);
90 } 79 }
91 80
92 @Test 81 @Test
93 - public void multiPath3() { 82 + public void dualEdgeMultiplePath() {
94 - g = new AdjacencyListsGraph<>(ImmutableSet.of(A, B, C, D, E, F, G, H), 83 + g = new AdjacencyListsGraph<>(of(A, B, C, D, E, F, G, H),
95 - ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(A, C, 3), 84 + of(new TestEdge(A, B, 1), new TestEdge(A, C, 3),
96 new TestEdge(B, D, 2), new TestEdge(B, C, 1), 85 new TestEdge(B, D, 2), new TestEdge(B, C, 1),
97 new TestEdge(B, E, 4), new TestEdge(C, E, 1), 86 new TestEdge(B, E, 4), new TestEdge(C, E, 1),
98 new TestEdge(D, H, 5), new TestEdge(D, E, 1), 87 new TestEdge(D, H, 5), new TestEdge(D, E, 1),
99 new TestEdge(E, F, 1), new TestEdge(F, D, 1), 88 new TestEdge(E, F, 1), new TestEdge(F, D, 1),
100 new TestEdge(F, G, 1), new TestEdge(F, H, 1), 89 new TestEdge(F, G, 1), new TestEdge(F, H, 1),
101 new TestEdge(A, E, 3), new TestEdge(B, D, 1))); 90 new TestEdge(A, E, 3), new TestEdge(B, D, 1)));
102 - 91 + executeSearch(graphSearch(), g, A, E, weight, 3, 3.0);
103 - GraphPathSearch<TestVertex, TestEdge> gs = graphSearch();
104 - Set<Path<TestVertex, TestEdge>> paths = gs.search(g, A, E, weight).paths();
105 - printPaths(paths);
106 - assertEquals("incorrect paths count", 3, paths.size());
107 - assertEquals("incorrect path cost", 3.0, paths.iterator().next().cost(), 0.1);
108 } 92 }
109 93
110 } 94 }
......
...@@ -4,6 +4,8 @@ import com.google.common.collect.ImmutableSet; ...@@ -4,6 +4,8 @@ import com.google.common.collect.ImmutableSet;
4 4
5 import java.util.Set; 5 import java.util.Set;
6 6
7 +import static com.google.common.collect.ImmutableSet.of;
8 +
7 /** 9 /**
8 * Base class for various graph-related tests. 10 * Base class for various graph-related tests.
9 */ 11 */
...@@ -35,11 +37,11 @@ public class GraphTest { ...@@ -35,11 +37,11 @@ public class GraphTest {
35 } 37 }
36 38
37 protected Set<TestVertex> vertices() { 39 protected Set<TestVertex> vertices() {
38 - return ImmutableSet.of(A, B, C, D, E, F, G, H); 40 + return of(A, B, C, D, E, F, G, H);
39 } 41 }
40 42
41 protected Set<TestEdge> edges() { 43 protected Set<TestEdge> edges() {
42 - return ImmutableSet.of(new TestEdge(A, B, 1), new TestEdge(A, C, 3), 44 + return of(new TestEdge(A, B, 1), new TestEdge(A, C, 3),
43 new TestEdge(B, D, 2), new TestEdge(B, C, 1), 45 new TestEdge(B, D, 2), new TestEdge(B, C, 1),
44 new TestEdge(B, E, 4), new TestEdge(C, E, 1), 46 new TestEdge(B, E, 4), new TestEdge(C, E, 1),
45 new TestEdge(D, H, 5), new TestEdge(D, E, 1), 47 new TestEdge(D, H, 5), new TestEdge(D, E, 1),
......
...@@ -9,6 +9,7 @@ import java.util.ArrayList; ...@@ -9,6 +9,7 @@ import java.util.ArrayList;
9 import java.util.Comparator; 9 import java.util.Comparator;
10 import java.util.Iterator; 10 import java.util.Iterator;
11 11
12 +import static com.google.common.collect.ImmutableList.of;
12 import static org.junit.Assert.*; 13 import static org.junit.Assert.*;
13 14
14 /** 15 /**
...@@ -17,25 +18,42 @@ import static org.junit.Assert.*; ...@@ -17,25 +18,42 @@ import static org.junit.Assert.*;
17 public class HeapTest { 18 public class HeapTest {
18 19
19 private ArrayList<Integer> data = 20 private ArrayList<Integer> data =
20 - new ArrayList<>(ImmutableList.of(6, 4, 5, 9, 8, 3, 2, 1, 7, 0)); 21 + new ArrayList<>(of(6, 4, 5, 9, 8, 3, 2, 1, 7, 0));
21 22
22 - private static final Comparator<Integer> ASCENDING = Ordering.natural().reverse(); 23 + private static final Comparator<Integer> MIN = Ordering.natural().reverse();
23 - private static final Comparator<Integer> DESCENDING = Ordering.natural(); 24 + private static final Comparator<Integer> MAX = Ordering.natural();
24 25
25 @Test 26 @Test
26 public void equality() { 27 public void equality() {
27 new EqualsTester() 28 new EqualsTester()
28 - .addEqualityGroup(new Heap<>(data, ASCENDING), 29 + .addEqualityGroup(new Heap<>(data, MIN),
29 - new Heap<>(data, ASCENDING)) 30 + new Heap<>(data, MIN))
30 - .addEqualityGroup(new Heap<>(data, DESCENDING)) 31 + .addEqualityGroup(new Heap<>(data, MAX))
31 .testEquals(); 32 .testEquals();
32 } 33 }
33 34
34 @Test 35 @Test
35 - public void ascending() { 36 + public void empty() {
36 - Heap<Integer> h = new Heap<>(data, ASCENDING); 37 + Heap<Integer> h = new Heap<>(new ArrayList<Integer>(), MIN);
38 + assertTrue("should be empty", h.isEmpty());
39 + assertEquals("incorrect size", 0, h.size());
40 + assertNull("no item expected", h.extreme());
41 + assertNull("no item expected", h.extractExtreme());
42 + }
43 +
44 + @Test
45 + public void insert() {
46 + Heap<Integer> h = new Heap<>(data, MIN);
37 assertEquals("incorrect size", 10, h.size()); 47 assertEquals("incorrect size", 10, h.size());
48 + h.insert(3);
49 + assertEquals("incorrect size", 11, h.size());
50 + }
51 +
52 + @Test
53 + public void minQueue() {
54 + Heap<Integer> h = new Heap<>(data, MIN);
38 assertFalse("should not be empty", h.isEmpty()); 55 assertFalse("should not be empty", h.isEmpty());
56 + assertEquals("incorrect size", 10, h.size());
39 assertEquals("incorrect extreme", (Integer) 0, h.extreme()); 57 assertEquals("incorrect extreme", (Integer) 0, h.extreme());
40 58
41 for (int i = 0, n = h.size(); i < n; i++) { 59 for (int i = 0, n = h.size(); i < n; i++) {
...@@ -45,10 +63,10 @@ public class HeapTest { ...@@ -45,10 +63,10 @@ public class HeapTest {
45 } 63 }
46 64
47 @Test 65 @Test
48 - public void descending() { 66 + public void maxQueue() {
49 - Heap<Integer> h = new Heap<>(data, DESCENDING); 67 + Heap<Integer> h = new Heap<>(data, MAX);
50 - assertEquals("incorrect size", 10, h.size());
51 assertFalse("should not be empty", h.isEmpty()); 68 assertFalse("should not be empty", h.isEmpty());
69 + assertEquals("incorrect size", 10, h.size());
52 assertEquals("incorrect extreme", (Integer) 9, h.extreme()); 70 assertEquals("incorrect extreme", (Integer) 9, h.extreme());
53 71
54 for (int i = h.size(); i > 0; i--) { 72 for (int i = h.size(); i > 0; i--) {
...@@ -58,29 +76,9 @@ public class HeapTest { ...@@ -58,29 +76,9 @@ public class HeapTest {
58 } 76 }
59 77
60 @Test 78 @Test
61 - public void empty() {
62 - Heap<Integer> h = new Heap<>(new ArrayList<Integer>(), ASCENDING);
63 - assertEquals("incorrect size", 0, h.size());
64 - assertTrue("should be empty", h.isEmpty());
65 - assertNull("no item expected", h.extreme());
66 - assertNull("no item expected", h.extractExtreme());
67 - }
68 -
69 - @Test
70 - public void insert() {
71 - Heap<Integer> h = new Heap<>(data, ASCENDING);
72 - assertEquals("incorrect size", 10, h.size());
73 - h.insert(3);
74 - assertEquals("incorrect size", 11, h.size());
75 - }
76 -
77 - @Test
78 public void iterator() { 79 public void iterator() {
79 - Heap<Integer> h = new Heap<>(data, ASCENDING); 80 + Heap<Integer> h = new Heap<>(data, MIN);
80 - Iterator<Integer> it = h.iterator(); 81 + assertTrue("should have next element", h.iterator().hasNext());
81 - while (it.hasNext()) {
82 - int item = it.next();
83 - }
84 } 82 }
85 83
86 } 84 }
......
...@@ -2,6 +2,8 @@ package org.onlab.graph; ...@@ -2,6 +2,8 @@ package org.onlab.graph;
2 2
3 import java.util.Objects; 3 import java.util.Objects;
4 4
5 +import static com.google.common.base.Objects.toStringHelper;
6 +
5 /** 7 /**
6 * Test edge. 8 * Test edge.
7 */ 9 */
...@@ -43,4 +45,11 @@ public class TestEdge extends AbstractEdge<TestVertex> { ...@@ -43,4 +45,11 @@ public class TestEdge extends AbstractEdge<TestVertex> {
43 } 45 }
44 return false; 46 return false;
45 } 47 }
48 +
49 + @Override
50 + public String toString() {
51 + return toStringHelper(this).add("src", src()).add("dst", dst()).
52 + add("weight", weight).toString();
53 + }
54 +
46 } 55 }
......
...@@ -16,11 +16,6 @@ public class TestVertex implements Vertex { ...@@ -16,11 +16,6 @@ public class TestVertex implements Vertex {
16 } 16 }
17 17
18 @Override 18 @Override
19 - public String toString() {
20 - return toStringHelper(this).add("name", name).toString();
21 - }
22 -
23 - @Override
24 public int hashCode() { 19 public int hashCode() {
25 return Objects.hash(name); 20 return Objects.hash(name);
26 } 21 }
...@@ -34,4 +29,9 @@ public class TestVertex implements Vertex { ...@@ -34,4 +29,9 @@ public class TestVertex implements Vertex {
34 return false; 29 return false;
35 } 30 }
36 31
32 + @Override
33 + public String toString() {
34 + return name;
35 + }
36 +
37 } 37 }
......