Skip to content

Commit

Permalink
common.graph: adding new EndpointPair-accepting overloads.
Browse files Browse the repository at this point in the history
RELNOTES=common.graph: added overloads to methods accepting pairs of nodes to also accept EndpointPair; changed behavior of *Graph.edges().contains() to allow undirected graphs to accept ordered EndpointPairs.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=218724287
  • Loading branch information
jrtom authored and cgdecker committed Oct 26, 2018
1 parent 64276db commit af3ee1c
Show file tree
Hide file tree
Showing 53 changed files with 1,591 additions and 87 deletions.
Expand Up @@ -16,7 +16,9 @@

package com.google.common.graph;

import static com.google.common.graph.GraphConstants.ENDPOINTS_MISMATCH;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;

import org.junit.Test;

Expand Down Expand Up @@ -68,10 +70,29 @@ public void outDegree_oneEdge() {
assertThat(graph.outDegree(N2)).isEqualTo(0);
}

@Test
public void hasEdgeConnecting_correct() {
putEdge(N1, N2);
assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(N1, N2))).isTrue();
}

@Test
public void hasEdgeConnecting_backwards() {
putEdge(N1, N2);
assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(N2, N1))).isFalse();
}

@Test
public void hasEdgeConnecting_mismatch() {
putEdge(N1, N2);
assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(N1, N2))).isFalse();
assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(N2, N1))).isFalse();
}

// Element Mutation

@Test
public void addEdge_existingNodes() {
public void putEdge_existingNodes() {
// Adding nodes initially for safety (insulating from possible future
// modifications to proxy methods)
addNode(N1);
Expand All @@ -80,11 +101,22 @@ public void addEdge_existingNodes() {
}

@Test
public void addEdge_existingEdgeBetweenSameNodes() {
putEdge(N1, N2);
public void putEdge_existingEdgeBetweenSameNodes() {
assertThat(putEdge(N1, N2)).isTrue();
assertThat(putEdge(N1, N2)).isFalse();
}

@Test
public void putEdge_orderMismatch() {
EndpointPair<Integer> endpoints = EndpointPair.unordered(N1, N2);
try {
putEdge(endpoints);
fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH);
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH);
}
}

public void removeEdge_antiparallelEdges() {
putEdge(N1, N2);
putEdge(N2, N1);
Expand All @@ -99,4 +131,16 @@ public void removeEdge_antiparallelEdges() {
assertThat(graph.predecessors(N1)).isEmpty();
assertThat(graph.edges()).isEmpty();
}

@Test
public void removeEdge_orderMismatch() {
putEdge(N1, N2);
EndpointPair<Integer> endpoints = EndpointPair.unordered(N1, N2);
try {
graph.removeEdge(endpoints);
fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH);
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH);
}
}
}
Expand Up @@ -16,6 +16,7 @@

package com.google.common.graph;

import static com.google.common.graph.GraphConstants.ENDPOINTS_MISMATCH;
import static com.google.common.graph.TestUtil.assertEdgeNotInGraphErrorMessage;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
Expand Down Expand Up @@ -59,6 +60,37 @@ public void validateSourceAndTarget() {
}
}

@Test
public void edges_containsOrderMismatch() {
addEdge(N1, N2, E12);
EndpointPair<Integer> endpointsN1N2 = EndpointPair.unordered(N1, N2);
EndpointPair<Integer> endpointsN2N1 = EndpointPair.unordered(N2, N1);
assertThat(network.asGraph().edges()).doesNotContain(endpointsN1N2);
assertThat(network.asGraph().edges()).doesNotContain(endpointsN2N1);
}

@Test
public void edgesConnecting_orderMismatch() {
addEdge(N1, N2, E12);
try {
Set<String> unused = network.edgesConnecting(EndpointPair.unordered(N1, N2));
fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH);
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH);
}
}

@Test
public void edgeConnectingOrNull_orderMismatch() {
addEdge(N1, N2, E12);
try {
String unused = network.edgeConnectingOrNull(EndpointPair.unordered(N1, N2));
fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH);
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH);
}
}

@Override
@Test
public void incidentNodes_oneEdge() {
Expand Down Expand Up @@ -187,14 +219,14 @@ public void addEdge_existingEdgeBetweenDifferentNodes() {
addEdge(N4, N5, E12);
fail(ERROR_ADDED_EXISTING_EDGE);
} catch (IllegalArgumentException e) {
assertThat(e.getMessage()).contains(ERROR_REUSE_EDGE);
assertThat(e).hasMessageThat().contains(ERROR_REUSE_EDGE);
}
try {
// Edge between same nodes but in reverse direction
addEdge(N2, N1, E12);
fail(ERROR_ADDED_EXISTING_EDGE);
} catch (IllegalArgumentException e) {
assertThat(e.getMessage()).contains(ERROR_REUSE_EDGE);
assertThat(e).hasMessageThat().contains(ERROR_REUSE_EDGE);
}
}

Expand All @@ -205,7 +237,18 @@ public void addEdge_parallelEdge() {
addEdge(N1, N2, EDGE_NOT_IN_GRAPH);
fail(ERROR_ADDED_PARALLEL_EDGE);
} catch (IllegalArgumentException e) {
assertThat(e.getMessage()).contains(ERROR_PARALLEL_EDGE);
assertThat(e).hasMessageThat().contains(ERROR_PARALLEL_EDGE);
}
}

@Test
public void addEdge_orderMismatch() {
EndpointPair<Integer> endpoints = EndpointPair.unordered(N1, N2);
try {
addEdge(endpoints, E12);
fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH);
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH);
}
}
}
Expand Up @@ -103,6 +103,13 @@ protected boolean putEdge(Integer n1, Integer n2) {
return graph.putEdge(n1, n2);
}

@CanIgnoreReturnValue
protected boolean putEdge(EndpointPair<Integer> endpoints) {
graph.addNode(endpoints.nodeU());
graph.addNode(endpoints.nodeV());
return graph.putEdge(endpoints);
}

@Before
public void init() {
graph = createGraph();
Expand Down
Expand Up @@ -120,6 +120,8 @@ protected boolean addNode(Integer n) {
* add an edge whose end-points don't already exist in the graph), you should <b>not</b> use this
* method.
*
* TODO(user): remove the addNode() calls, that's now contractually guaranteed
*
* @return {@code true} iff the graph was modified as a result of this call
*/
@CanIgnoreReturnValue
Expand All @@ -129,6 +131,12 @@ protected boolean addEdge(Integer n1, Integer n2, String e) {
return network.addEdge(n1, n2, e);
}

protected boolean addEdge(EndpointPair<Integer> endpoints, String e) {
network.addNode(endpoints.nodeU());
network.addNode(endpoints.nodeV());
return network.addEdge(endpoints, e);
}

@Before
public void init() {
network = createGraph();
Expand Down
Expand Up @@ -77,6 +77,20 @@ public void outDegree_oneEdge() {
assertThat(graph.outDegree(N2)).isEqualTo(1);
}

@Test
public void hasEdgeConnecting_correct() {
putEdge(N1, N2);
assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(N1, N2))).isTrue();
assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(N2, N1))).isTrue();
}

@Test
public void hasEdgeConnecting_mismatch() {
putEdge(N1, N2);
assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(N1, N2))).isTrue();
assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(N2, N1))).isTrue();
}

// Element Mutation

@Test
Expand Down
Expand Up @@ -32,6 +32,8 @@
* Test cases that do not require the graph to be undirected are found in superclasses.
*/
public abstract class AbstractUndirectedNetworkTest extends AbstractNetworkTest {
private static final EndpointPair<Integer> ENDPOINTS_N1N2 = EndpointPair.ordered(N1, N2);
private static final EndpointPair<Integer> ENDPOINTS_N2N1 = EndpointPair.ordered(N2, N1);

@After
public void validateUndirectedEdges() {
Expand All @@ -52,6 +54,27 @@ public void validateUndirectedEdges() {
}
}

@Test
public void edges_containsOrderMismatch() {
addEdge(N1, N2, E12);
assertThat(network.asGraph().edges()).contains(ENDPOINTS_N2N1);
assertThat(network.asGraph().edges()).contains(ENDPOINTS_N1N2);
}

@Test
public void edgesConnecting_orderMismatch() {
addEdge(N1, N2, E12);
assertThat(network.edgesConnecting(ENDPOINTS_N2N1)).containsExactly(E12);
assertThat(network.edgesConnecting(ENDPOINTS_N1N2)).containsExactly(E12);
}

@Test
public void edgeConnectingOrNull_orderMismatch() {
addEdge(N1, N2, E12);
assertThat(network.edgeConnectingOrNull(ENDPOINTS_N2N1)).isEqualTo(E12);
assertThat(network.edgeConnectingOrNull(ENDPOINTS_N1N2)).isEqualTo(E12);
}

@Test
public void edgesConnecting_oneEdge() {
addEdge(N1, N2, E12);
Expand Down Expand Up @@ -117,7 +140,7 @@ public void addEdge_existingNodes() {

@Test
public void addEdge_existingEdgeBetweenSameNodes() {
addEdge(N1, N2, E12);
assertThat(addEdge(N1, N2, E12)).isTrue();
ImmutableSet<String> edges = ImmutableSet.copyOf(network.edges());
assertThat(addEdge(N1, N2, E12)).isFalse();
assertThat(network.edges()).containsExactlyElementsIn(edges);
Expand Down Expand Up @@ -153,4 +176,10 @@ public void addEdge_parallelEdge() {
assertThat(e.getMessage()).contains(ERROR_PARALLEL_EDGE);
}
}

@Test
public void addEdge_orderMismatch() {
EndpointPair<Integer> endpoints = EndpointPair.ordered(N1, N2);
assertThat(addEdge(endpoints, E12)).isTrue();
}
}
Expand Up @@ -203,7 +203,7 @@ public void endpointPair_unmodifiableView() {
}

@Test
public void endpointPair_containment() {
public void endpointPair_undirected_contains() {
MutableGraph<Integer> undirectedGraph = GraphBuilder.undirected().allowsSelfLoops(true).build();
undirectedGraph.putEdge(N1, N1);
undirectedGraph.putEdge(N1, N2);
Expand All @@ -214,11 +214,32 @@ public void endpointPair_containment() {
assertThat(edges).contains(EndpointPair.unordered(N1, N2));
assertThat(edges).contains(EndpointPair.unordered(N2, N1)); // equal to unordered(N1, N2)

assertThat(edges).doesNotContain(EndpointPair.unordered(N2, N2));
assertThat(edges).doesNotContain(EndpointPair.ordered(N1, N2)); // graph not directed
// ordered endpoints OK for undirected graph (because ordering is irrelevant)
assertThat(edges).contains(EndpointPair.ordered(N1, N2));

assertThat(edges).doesNotContain(EndpointPair.unordered(N2, N2)); // edge not present
assertThat(edges).doesNotContain(EndpointPair.unordered(N3, N4)); // nodes not in graph
}

@Test
public void endpointPair_directed_contains() {
MutableGraph<Integer> directedGraph = GraphBuilder.directed().allowsSelfLoops(true).build();
directedGraph.putEdge(N1, N1);
directedGraph.putEdge(N1, N2);
Set<EndpointPair<Integer>> edges = directedGraph.edges();

assertThat(edges).hasSize(2);
assertThat(edges).contains(EndpointPair.ordered(N1, N1));
assertThat(edges).contains(EndpointPair.ordered(N1, N2));

// unordered endpoints not OK for directed graph (undefined behavior)
assertThat(edges).doesNotContain(EndpointPair.unordered(N1, N2));

assertThat(edges).doesNotContain(EndpointPair.ordered(N2, N1)); // wrong order
assertThat(edges).doesNotContain(EndpointPair.ordered(N2, N2)); // edge not present
assertThat(edges).doesNotContain(EndpointPair.ordered(N3, N4)); // nodes not in graph
}

private static void containsExactlySanityCheck(Collection<?> collection, Object... varargs) {
assertThat(collection).hasSize(varargs.length);
for (Object obj : varargs) {
Expand Down

0 comments on commit af3ee1c

Please sign in to comment.