/** * A proxy method that adds the node {@code n} to the graph being tested. In case of Immutable * graph implementations, this method should add {@code n} to the graph builder and build a new * graph with the current builder state. * * @return {@code true} iff the graph was modified as a result of this call */ @CanIgnoreReturnValue protected boolean addNode(Integer n) { return graph.addNode(n); }
/** * A proxy method that adds the edge {@code e} to the graph being tested. In case of Immutable * graph implementations, this method should add {@code e} to the graph builder and build a new * graph with the current builder state. * * <p>This method should be used in tests of specific implementations if you want to ensure * uniform behavior (including side effects) with how edges are added elsewhere in the tests. For * example, the existing implementations of this method explicitly add the supplied nodes to the * graph, and then call {@code graph.addEdge()} to connect the edge to the nodes; this is not part * of the contract of {@code graph.addEdge()} and is done for convenience. In cases where you want * to avoid such side effects (e.g., if you're testing what happens in your implementation if you * add an edge whose end-points don't already exist in the graph), you should <b>not</b> use this * method. * * @return {@code true} iff the graph was modified as a result of this call */ @CanIgnoreReturnValue protected boolean putEdge(Integer n1, Integer n2) { graph.addNode(n1); graph.addNode(n2); return graph.putEdge(n1, n2); }
@Test public void immutableGraph() { MutableGraph<String> mutableGraph = GraphBuilder.directed().build(); mutableGraph.addNode("A"); ImmutableGraph<String> immutableGraph = ImmutableGraph.copyOf(mutableGraph); assertThat(immutableGraph).isNotInstanceOf(MutableValueGraph.class); assertThat(immutableGraph).isEqualTo(mutableGraph); mutableGraph.addNode("B"); assertThat(immutableGraph).isNotEqualTo(mutableGraph); }
/** Creates a mutable copy of {@code graph} with the same nodes and edges. */ public static <N> MutableGraph<N> copyOf(Graph<N> graph) { MutableGraph<N> copy = GraphBuilder.from(graph).expectedNodeCount(graph.nodes().size()).build(); for (N node : graph.nodes()) { copy.addNode(node); } for (EndpointPair<N> edge : graph.edges()) { copy.putEdge(edge.nodeU(), edge.nodeV()); } return copy; }
private static <N> ImmutableGraph<N> graphWithNode(N node) { MutableGraph<N> graph = GraphBuilder.directed().build(); graph.addNode(node); return ImmutableGraph.copyOf(graph); }
private static ImmutableGraph<Character> createSingleRootGraph() { MutableGraph<Character> graph = GraphBuilder.directed().build(); graph.addNode('a'); return ImmutableGraph.copyOf(graph); }
/** * Returns the subgraph of {@code graph} induced by {@code nodes}. This subgraph is a new graph * that contains all of the nodes in {@code nodes}, and all of the {@link Graph#edges() edges} * from {@code graph} for which both nodes are contained by {@code nodes}. * * @throws IllegalArgumentException if any element in {@code nodes} is not a node in the graph */ public static <N> MutableGraph<N> inducedSubgraph(Graph<N> graph, Iterable<? extends N> nodes) { MutableGraph<N> subgraph = (nodes instanceof Collection) ? GraphBuilder.from(graph).expectedNodeCount(((Collection) nodes).size()).build() : GraphBuilder.from(graph).build(); for (N node : nodes) { subgraph.addNode(node); } for (N node : subgraph.nodes()) { for (N successorNode : graph.successors(node)) { if (subgraph.nodes().contains(successorNode)) { subgraph.putEdge(node, successorNode); } } } return subgraph; }
@Test public void customComparable() { MutableGraph<ComparableSubClass> graph = GraphBuilder.undirected().nodeOrder(ElementOrder.<ComparableSubClass>natural()).build(); ComparableSubClass node2 = new ComparableSubClass(2); ComparableSubClass node4 = new ComparableSubClass(4); ComparableSubClass node6 = new ComparableSubClass(6); ComparableSubClass node8 = new ComparableSubClass(8); graph.addNode(node4); graph.addNode(node2); graph.addNode(node6); graph.addNode(node8); assertThat(graph.nodeOrder().comparator()).isEqualTo(Ordering.natural()); assertThat(graph.nodes()).containsExactly(node2, node4, node6, node8).inOrder(); }
@Test public void hasCycle_disconnectedCyclicGraph() { for (MutableGraph<Integer> graph : graphsToTest) { graph.putEdge(1, 2); graph.putEdge(2, 1); // no-op in undirected case graph.addNode(3); } assertThat(hasCycle(directedGraph)).isTrue(); assertThat(hasCycle(undirectedGraph)).isFalse(); }
@Test public void customComparator() { Comparator<NonComparableSuperClass> comparator = new Comparator<NonComparableSuperClass>() { @Override public int compare(NonComparableSuperClass left, NonComparableSuperClass right) { return left.value.compareTo(right.value); } }; MutableGraph<NonComparableSuperClass> graph = GraphBuilder.undirected().nodeOrder(ElementOrder.sorted(comparator)).build(); NonComparableSuperClass node1 = new NonComparableSuperClass(1); NonComparableSuperClass node3 = new NonComparableSuperClass(3); NonComparableSuperClass node5 = new NonComparableSuperClass(5); NonComparableSuperClass node7 = new NonComparableSuperClass(7); graph.addNode(node1); graph.addNode(node7); graph.addNode(node5); graph.addNode(node3); assertThat(graph.nodeOrder().comparator()).isEqualTo(comparator); assertThat(graph.nodes()).containsExactly(node1, node3, node5, node7).inOrder(); }
/** * This test checks an implementation dependent feature. It tests that the method {@code addEdge} * will silently add the missing nodes to the graph, then add the edge connecting them. We are not * using the proxy methods here as we want to test {@code addEdge} when the end-points are not * elements of the graph. */ @Test public void addEdge_nodesNotInGraph() { graph.addNode(N1); assertTrue(graph.putEdge(N1, N5)); assertTrue(graph.putEdge(N4, N1)); assertTrue(graph.putEdge(N2, N3)); assertThat(graph.nodes()).containsExactly(N1, N5, N4, N2, N3).inOrder(); assertThat(graph.successors(N1)).containsExactly(N5); assertThat(graph.successors(N2)).containsExactly(N3); assertThat(graph.successors(N3)).isEmpty(); assertThat(graph.successors(N4)).containsExactly(N1); assertThat(graph.successors(N5)).isEmpty(); } }
/** * This test checks an implementation dependent feature. It tests that the method {@code addEdge} * will silently add the missing nodes to the graph, then add the edge connecting them. We are not * using the proxy methods here as we want to test {@code addEdge} when the end-points are not * elements of the graph. */ @Test public void addEdge_nodesNotInGraph() { graph.addNode(N1); assertTrue(graph.putEdge(N1, N5)); assertTrue(graph.putEdge(N4, N1)); assertTrue(graph.putEdge(N2, N3)); assertThat(graph.nodes()).containsExactly(N1, N5, N4, N2, N3).inOrder(); assertThat(graph.adjacentNodes(N1)).containsExactly(N4, N5); assertThat(graph.adjacentNodes(N2)).containsExactly(N3); assertThat(graph.adjacentNodes(N3)).containsExactly(N2); assertThat(graph.adjacentNodes(N4)).containsExactly(N1); assertThat(graph.adjacentNodes(N5)).containsExactly(N1); } }
@Test public void endpointPair_undirectedGraph() { MutableGraph<Integer> undirectedGraph = GraphBuilder.undirected().allowsSelfLoops(true).build(); undirectedGraph.addNode(N0); undirectedGraph.putEdge(N1, N2); undirectedGraph.putEdge(N2, N1); // does nothing undirectedGraph.putEdge(N1, N3); undirectedGraph.putEdge(N4, N4); containsExactlySanityCheck( undirectedGraph.edges(), EndpointPair.unordered(N1, N2), EndpointPair.unordered(N1, N3), EndpointPair.unordered(N4, N4)); }
@Test public void endpointPair_directedGraph() { MutableGraph<Integer> directedGraph = GraphBuilder.directed().allowsSelfLoops(true).build(); directedGraph.addNode(N0); directedGraph.putEdge(N1, N2); directedGraph.putEdge(N2, N1); directedGraph.putEdge(N1, N3); directedGraph.putEdge(N4, N4); containsExactlySanityCheck( directedGraph.edges(), EndpointPair.ordered(N1, N2), EndpointPair.ordered(N2, N1), EndpointPair.ordered(N1, N3), EndpointPair.ordered(N4, N4)); }
@Test public void transitiveClosure_undirectedGraph() { MutableGraph<Integer> undirectedGraph = GraphBuilder.undirected().allowsSelfLoops(false).build(); undirectedGraph.putEdge(N1, N2); undirectedGraph.putEdge(N1, N3); undirectedGraph.putEdge(N2, N3); undirectedGraph.addNode(N4); MutableGraph<Integer> expectedClosure = GraphBuilder.undirected().allowsSelfLoops(true).build(); expectedClosure.putEdge(N1, N1); expectedClosure.putEdge(N1, N2); expectedClosure.putEdge(N1, N3); expectedClosure.putEdge(N2, N2); expectedClosure.putEdge(N2, N3); expectedClosure.putEdge(N3, N3); expectedClosure.putEdge(N4, N4); checkTransitiveClosure(undirectedGraph, expectedClosure); }
@Test public void transitiveClosure_directedGraph() { MutableGraph<Integer> directedGraph = GraphBuilder.directed().allowsSelfLoops(false).build(); directedGraph.putEdge(N1, N2); directedGraph.putEdge(N1, N3); directedGraph.putEdge(N2, N3); directedGraph.addNode(N4); MutableGraph<Integer> expectedClosure = GraphBuilder.directed().allowsSelfLoops(true).build(); expectedClosure.putEdge(N1, N1); expectedClosure.putEdge(N1, N2); expectedClosure.putEdge(N1, N3); expectedClosure.putEdge(N2, N2); expectedClosure.putEdge(N2, N3); expectedClosure.putEdge(N3, N3); expectedClosure.putEdge(N4, N4); checkTransitiveClosure(directedGraph, expectedClosure); }