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,57 +54,41 @@ public class DijkstraGraphSearchTest extends BreadthFirstSearchTest { ...@@ -54,57 +54,41 @@ 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),
78 - new TestEdge(D, E, 1), 73 + new TestEdge(D, E, 1),
79 - new TestEdge(D, F, 1), 74 + new TestEdge(D, F, 1),
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,16 +37,16 @@ public class GraphTest { ...@@ -35,16 +37,16 @@ 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),
46 - new TestEdge(E, F, 1), new TestEdge(F, D, 1), 48 + new TestEdge(E, F, 1), new TestEdge(F, D, 1),
47 - new TestEdge(F, G, 1), new TestEdge(F, H, 1)); 49 + new TestEdge(F, G, 1), new TestEdge(F, H, 1));
48 } 50 }
49 51
50 } 52 }
......
...@@ -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 }
......