1 /* 2 * Copyright (C) 2014 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.graph; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.TruthJUnit.assume; 21 import static org.junit.Assert.assertThrows; 22 import static org.junit.Assert.assertTrue; 23 24 import com.google.common.testing.EqualsTester; 25 import java.util.Set; 26 import org.junit.After; 27 import org.junit.Test; 28 29 /** 30 * Abstract base class for testing undirected {@link Graph} implementations defined in this package. 31 */ 32 public abstract class AbstractStandardUndirectedGraphTest extends AbstractGraphTest { 33 34 @After validateUndirectedEdges()35 public void validateUndirectedEdges() { 36 for (Integer node : graph.nodes()) { 37 new EqualsTester() 38 .addEqualityGroup( 39 graph.predecessors(node), graph.successors(node), graph.adjacentNodes(node)) 40 .testEquals(); 41 } 42 } 43 44 @Override 45 @Test nodes_checkReturnedSetMutability()46 public void nodes_checkReturnedSetMutability() { 47 assume().that(graphIsMutable()).isTrue(); 48 49 Set<Integer> nodes = graph.nodes(); 50 assertThrows(UnsupportedOperationException.class, () -> nodes.add(N2)); 51 addNode(N1); 52 assertThat(graph.nodes()).containsExactlyElementsIn(nodes); 53 } 54 55 @Override 56 @Test adjacentNodes_checkReturnedSetMutability()57 public void adjacentNodes_checkReturnedSetMutability() { 58 assume().that(graphIsMutable()).isTrue(); 59 60 addNode(N1); 61 Set<Integer> adjacentNodes = graph.adjacentNodes(N1); 62 assertThrows(UnsupportedOperationException.class, () -> adjacentNodes.add(N2)); 63 putEdge(N1, N2); 64 assertThat(graph.adjacentNodes(N1)).containsExactlyElementsIn(adjacentNodes); 65 } 66 67 @Override 68 @Test predecessors_checkReturnedSetMutability()69 public void predecessors_checkReturnedSetMutability() { 70 assume().that(graphIsMutable()).isTrue(); 71 72 addNode(N2); 73 Set<Integer> predecessors = graph.predecessors(N2); 74 assertThrows(UnsupportedOperationException.class, () -> predecessors.add(N1)); 75 putEdge(N1, N2); 76 assertThat(graph.predecessors(N2)).containsExactlyElementsIn(predecessors); 77 } 78 79 @Override 80 @Test successors_checkReturnedSetMutability()81 public void successors_checkReturnedSetMutability() { 82 assume().that(graphIsMutable()).isTrue(); 83 84 addNode(N1); 85 Set<Integer> successors = graph.successors(N1); 86 assertThrows(UnsupportedOperationException.class, () -> successors.add(N2)); 87 putEdge(N1, N2); 88 assertThat(graph.successors(N1)).containsExactlyElementsIn(successors); 89 } 90 91 @Override 92 @Test incidentEdges_checkReturnedSetMutability()93 public void incidentEdges_checkReturnedSetMutability() { 94 assume().that(graphIsMutable()).isTrue(); 95 96 addNode(N1); 97 Set<EndpointPair<Integer>> incidentEdges = graph.incidentEdges(N1); 98 assertThrows( 99 UnsupportedOperationException.class, 100 () -> incidentEdges.add(EndpointPair.unordered(N1, N2))); 101 putEdge(N1, N2); 102 assertThat(incidentEdges).containsExactlyElementsIn(graph.incidentEdges(N1)); 103 } 104 105 @Test predecessors_oneEdge()106 public void predecessors_oneEdge() { 107 putEdge(N1, N2); 108 assertThat(graph.predecessors(N2)).containsExactly(N1); 109 assertThat(graph.predecessors(N1)).containsExactly(N2); 110 } 111 112 @Test successors_oneEdge()113 public void successors_oneEdge() { 114 putEdge(N1, N2); 115 assertThat(graph.successors(N1)).containsExactly(N2); 116 assertThat(graph.successors(N2)).containsExactly(N1); 117 } 118 119 @Test incidentEdges_oneEdge()120 public void incidentEdges_oneEdge() { 121 putEdge(N1, N2); 122 EndpointPair<Integer> expectedEndpoints = EndpointPair.unordered(N1, N2); 123 assertThat(graph.incidentEdges(N1)).containsExactly(expectedEndpoints); 124 assertThat(graph.incidentEdges(N2)).containsExactly(expectedEndpoints); 125 } 126 127 @Test inDegree_oneEdge()128 public void inDegree_oneEdge() { 129 putEdge(N1, N2); 130 assertThat(graph.inDegree(N2)).isEqualTo(1); 131 assertThat(graph.inDegree(N1)).isEqualTo(1); 132 } 133 134 @Test outDegree_oneEdge()135 public void outDegree_oneEdge() { 136 putEdge(N1, N2); 137 assertThat(graph.outDegree(N1)).isEqualTo(1); 138 assertThat(graph.outDegree(N2)).isEqualTo(1); 139 } 140 141 @Test hasEdgeConnecting_correct()142 public void hasEdgeConnecting_correct() { 143 putEdge(N1, N2); 144 assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(N1, N2))).isTrue(); 145 assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(N2, N1))).isTrue(); 146 } 147 148 @Test hasEdgeConnecting_mismatch()149 public void hasEdgeConnecting_mismatch() { 150 putEdge(N1, N2); 151 assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(N1, N2))).isFalse(); 152 assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(N2, N1))).isFalse(); 153 } 154 155 @Test adjacentNodes_selfLoop()156 public void adjacentNodes_selfLoop() { 157 assume().that(graph.allowsSelfLoops()).isTrue(); 158 159 putEdge(N1, N1); 160 putEdge(N1, N2); 161 assertThat(graph.adjacentNodes(N1)).containsExactly(N1, N2); 162 } 163 164 @Test predecessors_selfLoop()165 public void predecessors_selfLoop() { 166 assume().that(graph.allowsSelfLoops()).isTrue(); 167 168 putEdge(N1, N1); 169 assertThat(graph.predecessors(N1)).containsExactly(N1); 170 putEdge(N1, N2); 171 assertThat(graph.predecessors(N1)).containsExactly(N1, N2); 172 } 173 174 @Test successors_selfLoop()175 public void successors_selfLoop() { 176 assume().that(graph.allowsSelfLoops()).isTrue(); 177 178 putEdge(N1, N1); 179 assertThat(graph.successors(N1)).containsExactly(N1); 180 putEdge(N2, N1); 181 assertThat(graph.successors(N1)).containsExactly(N1, N2); 182 } 183 184 @Test incidentEdges_selfLoop()185 public void incidentEdges_selfLoop() { 186 assume().that(graph.allowsSelfLoops()).isTrue(); 187 188 putEdge(N1, N1); 189 assertThat(graph.incidentEdges(N1)).containsExactly(EndpointPair.unordered(N1, N1)); 190 putEdge(N1, N2); 191 assertThat(graph.incidentEdges(N1)) 192 .containsExactly(EndpointPair.unordered(N1, N1), EndpointPair.unordered(N1, N2)); 193 } 194 195 @Test degree_selfLoop()196 public void degree_selfLoop() { 197 assume().that(graph.allowsSelfLoops()).isTrue(); 198 199 putEdge(N1, N1); 200 assertThat(graph.degree(N1)).isEqualTo(2); 201 putEdge(N1, N2); 202 assertThat(graph.degree(N1)).isEqualTo(3); 203 } 204 205 @Test inDegree_selfLoop()206 public void inDegree_selfLoop() { 207 assume().that(graph.allowsSelfLoops()).isTrue(); 208 209 putEdge(N1, N1); 210 assertThat(graph.inDegree(N1)).isEqualTo(2); 211 putEdge(N1, N2); 212 assertThat(graph.inDegree(N1)).isEqualTo(3); 213 } 214 215 @Test outDegree_selfLoop()216 public void outDegree_selfLoop() { 217 assume().that(graph.allowsSelfLoops()).isTrue(); 218 219 putEdge(N1, N1); 220 assertThat(graph.outDegree(N1)).isEqualTo(2); 221 putEdge(N2, N1); 222 assertThat(graph.outDegree(N1)).isEqualTo(3); 223 } 224 225 // Stable order tests 226 227 // Note: Stable order means that the ordering doesn't change between iterations and versions. 228 // Ideally, the ordering in test should never be updated. 229 @Test stableIncidentEdgeOrder_edges_returnsInStableOrder()230 public void stableIncidentEdgeOrder_edges_returnsInStableOrder() { 231 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 232 233 populateTShapedGraph(); 234 235 assertThat(graph.edges()) 236 .containsExactly( 237 EndpointPair.unordered(1, 2), 238 EndpointPair.unordered(1, 4), 239 EndpointPair.unordered(1, 3), 240 EndpointPair.unordered(4, 5)) 241 .inOrder(); 242 } 243 244 @Test stableIncidentEdgeOrder_adjacentNodes_returnsInConnectingEdgeInsertionOrder()245 public void stableIncidentEdgeOrder_adjacentNodes_returnsInConnectingEdgeInsertionOrder() { 246 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 247 248 populateTShapedGraph(); 249 250 assertThat(graph.adjacentNodes(1)).containsExactly(2, 4, 3).inOrder(); 251 } 252 253 @Test stableIncidentEdgeOrder_predecessors_returnsInConnectingEdgeInsertionOrder()254 public void stableIncidentEdgeOrder_predecessors_returnsInConnectingEdgeInsertionOrder() { 255 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 256 257 populateTShapedGraph(); 258 259 assertThat(graph.adjacentNodes(1)).containsExactly(2, 4, 3).inOrder(); 260 } 261 262 @Test stableIncidentEdgeOrder_successors_returnsInConnectingEdgeInsertionOrder()263 public void stableIncidentEdgeOrder_successors_returnsInConnectingEdgeInsertionOrder() { 264 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 265 266 populateTShapedGraph(); 267 268 assertThat(graph.adjacentNodes(1)).containsExactly(2, 4, 3).inOrder(); 269 } 270 271 @Test stableIncidentEdgeOrder_incidentEdges_returnsInEdgeInsertionOrder()272 public void stableIncidentEdgeOrder_incidentEdges_returnsInEdgeInsertionOrder() { 273 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 274 275 populateTShapedGraph(); 276 277 assertThat(graph.incidentEdges(1)) 278 .containsExactly( 279 EndpointPair.unordered(1, 2), 280 EndpointPair.unordered(1, 4), 281 EndpointPair.unordered(1, 3)) 282 .inOrder(); 283 } 284 285 @Test stableIncidentEdgeOrder_incidentEdges_withSelfLoop_returnsInEdgeInsertionOrder()286 public void stableIncidentEdgeOrder_incidentEdges_withSelfLoop_returnsInEdgeInsertionOrder() { 287 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 288 assume().that(graph.allowsSelfLoops()).isTrue(); 289 290 putEdge(2, 1); 291 putEdge(1, 1); 292 putEdge(1, 3); 293 294 assertThat(graph.incidentEdges(1)) 295 .containsExactly( 296 EndpointPair.unordered(2, 1), 297 EndpointPair.unordered(1, 1), 298 EndpointPair.unordered(1, 3)) 299 .inOrder(); 300 } 301 302 /** 303 * Populates the graph with nodes and edges in a star shape with node `1` in the middle. 304 * 305 * <p>Note that the edges are added in a shuffled order to properly test the effect of the 306 * insertion order. 307 */ populateTShapedGraph()308 private void populateTShapedGraph() { 309 putEdge(2, 1); 310 putEdge(1, 4); 311 putEdge(1, 3); 312 putEdge(1, 2); // Duplicate 313 putEdge(4, 5); 314 } 315 316 // Element Mutation 317 318 @Test putEdge_existingNodes()319 public void putEdge_existingNodes() { 320 assume().that(graphIsMutable()).isTrue(); 321 322 // Adding nodes initially for safety (insulating from possible future 323 // modifications to proxy methods) 324 addNode(N1); 325 addNode(N2); 326 327 assertThat(graphAsMutableGraph.putEdge(N1, N2)).isTrue(); 328 } 329 330 @Test putEdge_existingEdgeBetweenSameNodes()331 public void putEdge_existingEdgeBetweenSameNodes() { 332 assume().that(graphIsMutable()).isTrue(); 333 334 putEdge(N1, N2); 335 336 assertThat(graphAsMutableGraph.putEdge(N2, N1)).isFalse(); 337 } 338 339 /** 340 * Tests that the method {@code putEdge} will silently add the missing nodes to the graph, then 341 * add the edge connecting them. We are not using the proxy methods here as we want to test {@code 342 * putEdge} when the end-points are not elements of the graph. 343 */ 344 @Test putEdge_nodesNotInGraph()345 public void putEdge_nodesNotInGraph() { 346 assume().that(graphIsMutable()).isTrue(); 347 348 graphAsMutableGraph.addNode(N1); 349 assertTrue(graphAsMutableGraph.putEdge(N1, N5)); 350 assertTrue(graphAsMutableGraph.putEdge(N4, N1)); 351 assertTrue(graphAsMutableGraph.putEdge(N2, N3)); 352 assertThat(graph.nodes()).containsExactly(N1, N5, N4, N2, N3).inOrder(); 353 assertThat(graph.adjacentNodes(N1)).containsExactly(N4, N5); 354 assertThat(graph.adjacentNodes(N2)).containsExactly(N3); 355 assertThat(graph.adjacentNodes(N3)).containsExactly(N2); 356 assertThat(graph.adjacentNodes(N4)).containsExactly(N1); 357 assertThat(graph.adjacentNodes(N5)).containsExactly(N1); 358 } 359 360 @Test putEdge_doesntAllowSelfLoops()361 public void putEdge_doesntAllowSelfLoops() { 362 assume().that(graphIsMutable()).isTrue(); 363 assume().that(graph.allowsSelfLoops()).isFalse(); 364 365 IllegalArgumentException e = 366 assertThrows(IllegalArgumentException.class, () -> putEdge(N1, N1)); 367 assertThat(e).hasMessageThat().contains(ERROR_SELF_LOOP); 368 } 369 370 @Test putEdge_allowsSelfLoops()371 public void putEdge_allowsSelfLoops() { 372 assume().that(graphIsMutable()).isTrue(); 373 assume().that(graph.allowsSelfLoops()).isTrue(); 374 375 assertThat(graphAsMutableGraph.putEdge(N1, N1)).isTrue(); 376 assertThat(graph.adjacentNodes(N1)).containsExactly(N1); 377 } 378 379 @Test putEdge_existingSelfLoopEdgeBetweenSameNodes()380 public void putEdge_existingSelfLoopEdgeBetweenSameNodes() { 381 assume().that(graphIsMutable()).isTrue(); 382 assume().that(graph.allowsSelfLoops()).isTrue(); 383 384 putEdge(N1, N1); 385 assertThat(graphAsMutableGraph.putEdge(N1, N1)).isFalse(); 386 } 387 388 @Test removeEdge_antiparallelEdges()389 public void removeEdge_antiparallelEdges() { 390 assume().that(graphIsMutable()).isTrue(); 391 392 putEdge(N1, N2); 393 putEdge(N2, N1); // no-op 394 395 assertThat(graphAsMutableGraph.removeEdge(N1, N2)).isTrue(); 396 assertThat(graph.adjacentNodes(N1)).isEmpty(); 397 assertThat(graph.edges()).isEmpty(); 398 assertThat(graphAsMutableGraph.removeEdge(N2, N1)).isFalse(); 399 } 400 401 @Test removeNode_existingNodeWithSelfLoopEdge()402 public void removeNode_existingNodeWithSelfLoopEdge() { 403 assume().that(graphIsMutable()).isTrue(); 404 assume().that(graph.allowsSelfLoops()).isTrue(); 405 406 addNode(N1); 407 putEdge(N1, N1); 408 assertThat(graphAsMutableGraph.removeNode(N1)).isTrue(); 409 assertThat(graph.nodes()).isEmpty(); 410 } 411 412 @Test removeEdge_existingSelfLoopEdge()413 public void removeEdge_existingSelfLoopEdge() { 414 assume().that(graphIsMutable()).isTrue(); 415 assume().that(graph.allowsSelfLoops()).isTrue(); 416 417 putEdge(N1, N1); 418 assertThat(graphAsMutableGraph.removeEdge(N1, N1)).isTrue(); 419 assertThat(graph.nodes()).containsExactly(N1); 420 assertThat(graph.adjacentNodes(N1)).isEmpty(); 421 } 422 } 423