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.graph.GraphConstants.ENDPOINTS_MISMATCH; 20 import static com.google.common.truth.Truth.assertThat; 21 import static com.google.common.truth.TruthJUnit.assume; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 25 import java.util.Set; 26 import org.junit.Test; 27 28 /** 29 * Abstract base class for testing directed {@link Graph} implementations defined in this package. 30 */ 31 public abstract class AbstractStandardDirectedGraphTest extends AbstractGraphTest { 32 33 @Override 34 @Test nodes_checkReturnedSetMutability()35 public void nodes_checkReturnedSetMutability() { 36 assume().that(graphIsMutable()).isTrue(); 37 38 Set<Integer> nodes = graph.nodes(); 39 try { 40 nodes.add(N2); 41 fail(ERROR_MODIFIABLE_SET); 42 } catch (UnsupportedOperationException e) { 43 addNode(N1); 44 assertThat(graph.nodes()).containsExactlyElementsIn(nodes); 45 } 46 } 47 48 @Override 49 @Test adjacentNodes_checkReturnedSetMutability()50 public void adjacentNodes_checkReturnedSetMutability() { 51 assume().that(graphIsMutable()).isTrue(); 52 53 addNode(N1); 54 Set<Integer> adjacentNodes = graph.adjacentNodes(N1); 55 try { 56 adjacentNodes.add(N2); 57 fail(ERROR_MODIFIABLE_SET); 58 } catch (UnsupportedOperationException e) { 59 putEdge(N1, N2); 60 assertThat(graph.adjacentNodes(N1)).containsExactlyElementsIn(adjacentNodes); 61 } 62 } 63 64 @Override 65 @Test predecessors_checkReturnedSetMutability()66 public void predecessors_checkReturnedSetMutability() { 67 assume().that(graphIsMutable()).isTrue(); 68 69 addNode(N2); 70 Set<Integer> predecessors = graph.predecessors(N2); 71 try { 72 predecessors.add(N1); 73 fail(ERROR_MODIFIABLE_SET); 74 } catch (UnsupportedOperationException e) { 75 putEdge(N1, N2); 76 assertThat(graph.predecessors(N2)).containsExactlyElementsIn(predecessors); 77 } 78 } 79 80 @Override 81 @Test successors_checkReturnedSetMutability()82 public void successors_checkReturnedSetMutability() { 83 assume().that(graphIsMutable()).isTrue(); 84 85 addNode(N1); 86 Set<Integer> successors = graph.successors(N1); 87 try { 88 successors.add(N2); 89 fail(ERROR_MODIFIABLE_SET); 90 } catch (UnsupportedOperationException e) { 91 putEdge(N1, N2); 92 assertThat(successors).containsExactlyElementsIn(graph.successors(N1)); 93 } 94 } 95 96 @Override 97 @Test incidentEdges_checkReturnedSetMutability()98 public void incidentEdges_checkReturnedSetMutability() { 99 assume().that(graphIsMutable()).isTrue(); 100 101 addNode(N1); 102 Set<EndpointPair<Integer>> incidentEdges = graph.incidentEdges(N1); 103 try { 104 incidentEdges.add(EndpointPair.ordered(N1, N2)); 105 fail(ERROR_MODIFIABLE_SET); 106 } catch (UnsupportedOperationException e) { 107 putEdge(N1, N2); 108 assertThat(incidentEdges).containsExactlyElementsIn(graph.incidentEdges(N1)); 109 } 110 } 111 112 @Test predecessors_oneEdge()113 public void predecessors_oneEdge() { 114 putEdge(N1, N2); 115 assertThat(graph.predecessors(N2)).containsExactly(N1); 116 // Edge direction handled correctly 117 assertThat(graph.predecessors(N1)).isEmpty(); 118 } 119 120 @Test successors_oneEdge()121 public void successors_oneEdge() { 122 putEdge(N1, N2); 123 assertThat(graph.successors(N1)).containsExactly(N2); 124 // Edge direction handled correctly 125 assertThat(graph.successors(N2)).isEmpty(); 126 } 127 128 @Test incidentEdges_oneEdge()129 public void incidentEdges_oneEdge() { 130 putEdge(N1, N2); 131 EndpointPair<Integer> expectedEndpoints = EndpointPair.ordered(N1, N2); 132 assertThat(graph.incidentEdges(N1)).containsExactly(expectedEndpoints); 133 assertThat(graph.incidentEdges(N2)).containsExactly(expectedEndpoints); 134 } 135 136 @Test inDegree_oneEdge()137 public void inDegree_oneEdge() { 138 putEdge(N1, N2); 139 assertThat(graph.inDegree(N2)).isEqualTo(1); 140 // Edge direction handled correctly 141 assertThat(graph.inDegree(N1)).isEqualTo(0); 142 } 143 144 @Test outDegree_oneEdge()145 public void outDegree_oneEdge() { 146 putEdge(N1, N2); 147 assertThat(graph.outDegree(N1)).isEqualTo(1); 148 // Edge direction handled correctly 149 assertThat(graph.outDegree(N2)).isEqualTo(0); 150 } 151 152 @Test hasEdgeConnecting_correct()153 public void hasEdgeConnecting_correct() { 154 putEdge(N1, N2); 155 assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(N1, N2))).isTrue(); 156 } 157 158 @Test hasEdgeConnecting_backwards()159 public void hasEdgeConnecting_backwards() { 160 putEdge(N1, N2); 161 assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(N2, N1))).isFalse(); 162 } 163 164 @Test hasEdgeConnecting_mismatch()165 public void hasEdgeConnecting_mismatch() { 166 putEdge(N1, N2); 167 assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(N1, N2))).isFalse(); 168 assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(N2, N1))).isFalse(); 169 } 170 171 @Test adjacentNodes_selfLoop()172 public void adjacentNodes_selfLoop() { 173 assume().that(graph.allowsSelfLoops()).isTrue(); 174 175 putEdge(N1, N1); 176 putEdge(N1, N2); 177 assertThat(graph.adjacentNodes(N1)).containsExactly(N1, N2); 178 } 179 180 @Test predecessors_selfLoop()181 public void predecessors_selfLoop() { 182 assume().that(graph.allowsSelfLoops()).isTrue(); 183 184 putEdge(N1, N1); 185 assertThat(graph.predecessors(N1)).containsExactly(N1); 186 putEdge(N4, N1); 187 assertThat(graph.predecessors(N1)).containsExactly(N1, N4); 188 } 189 190 @Test successors_selfLoop()191 public void successors_selfLoop() { 192 assume().that(graph.allowsSelfLoops()).isTrue(); 193 194 putEdge(N1, N1); 195 assertThat(graph.successors(N1)).containsExactly(N1); 196 putEdge(N1, N2); 197 assertThat(graph.successors(N1)).containsExactly(N1, N2); 198 } 199 200 @Test incidentEdges_selfLoop()201 public void incidentEdges_selfLoop() { 202 assume().that(graph.allowsSelfLoops()).isTrue(); 203 204 putEdge(N1, N1); 205 assertThat(graph.incidentEdges(N1)).containsExactly(EndpointPair.ordered(N1, N1)); 206 putEdge(N1, N2); 207 assertThat(graph.incidentEdges(N1)) 208 .containsExactly(EndpointPair.ordered(N1, N1), EndpointPair.ordered(N1, N2)); 209 } 210 211 @Test degree_selfLoop()212 public void degree_selfLoop() { 213 assume().that(graph.allowsSelfLoops()).isTrue(); 214 215 putEdge(N1, N1); 216 assertThat(graph.degree(N1)).isEqualTo(2); 217 putEdge(N1, N2); 218 assertThat(graph.degree(N1)).isEqualTo(3); 219 } 220 221 @Test inDegree_selfLoop()222 public void inDegree_selfLoop() { 223 assume().that(graph.allowsSelfLoops()).isTrue(); 224 225 putEdge(N1, N1); 226 assertThat(graph.inDegree(N1)).isEqualTo(1); 227 putEdge(N4, N1); 228 assertThat(graph.inDegree(N1)).isEqualTo(2); 229 } 230 231 @Test outDegree_selfLoop()232 public void outDegree_selfLoop() { 233 assume().that(graph.allowsSelfLoops()).isTrue(); 234 235 putEdge(N1, N1); 236 assertThat(graph.outDegree(N1)).isEqualTo(1); 237 putEdge(N1, N2); 238 assertThat(graph.outDegree(N1)).isEqualTo(2); 239 } 240 241 // Stable order tests 242 243 // Note: Stable order means that the ordering doesn't change between iterations and versions. 244 // Ideally, the ordering in test should never be updated. 245 @Test stableIncidentEdgeOrder_edges_returnsInStableOrder()246 public void stableIncidentEdgeOrder_edges_returnsInStableOrder() { 247 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 248 249 populateStarShapedGraph(); 250 251 assertThat(graph.edges()) 252 .containsExactly( 253 EndpointPair.ordered(2, 1), 254 EndpointPair.ordered(1, 4), 255 EndpointPair.ordered(1, 3), 256 EndpointPair.ordered(1, 2), 257 EndpointPair.ordered(3, 1), 258 EndpointPair.ordered(5, 1)) 259 .inOrder(); 260 } 261 262 @Test stableIncidentEdgeOrder_adjacentNodes_returnsInConnectingEdgeInsertionOrder()263 public void stableIncidentEdgeOrder_adjacentNodes_returnsInConnectingEdgeInsertionOrder() { 264 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 265 266 populateStarShapedGraph(); 267 268 assertThat(graph.adjacentNodes(1)).containsExactly(2, 4, 3, 5).inOrder(); 269 } 270 271 @Test stableIncidentEdgeOrder_predecessors_returnsInConnectingEdgeInsertionOrder()272 public void stableIncidentEdgeOrder_predecessors_returnsInConnectingEdgeInsertionOrder() { 273 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 274 275 populateStarShapedGraph(); 276 277 assertThat(graph.predecessors(1)).containsExactly(2, 5, 3).inOrder(); 278 } 279 280 @Test stableIncidentEdgeOrder_successors_returnsInConnectingEdgeInsertionOrder()281 public void stableIncidentEdgeOrder_successors_returnsInConnectingEdgeInsertionOrder() { 282 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 283 284 populateStarShapedGraph(); 285 286 assertThat(graph.successors(1)).containsExactly(4, 3, 2).inOrder(); 287 } 288 289 @Test stableIncidentEdgeOrder_incidentEdges_returnsInEdgeInsertionOrder()290 public void stableIncidentEdgeOrder_incidentEdges_returnsInEdgeInsertionOrder() { 291 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 292 293 populateStarShapedGraph(); 294 295 assertThat(graph.incidentEdges(1)) 296 .containsExactly( 297 EndpointPair.ordered(2, 1), 298 EndpointPair.ordered(1, 4), 299 EndpointPair.ordered(1, 3), 300 EndpointPair.ordered(5, 1), 301 EndpointPair.ordered(1, 2), 302 EndpointPair.ordered(3, 1)) 303 .inOrder(); 304 } 305 306 @Test stableIncidentEdgeOrder_incidentEdges_withSelfLoop_returnsInEdgeInsertionOrder()307 public void stableIncidentEdgeOrder_incidentEdges_withSelfLoop_returnsInEdgeInsertionOrder() { 308 assume().that(graph.incidentEdgeOrder().type()).isEqualTo(ElementOrder.Type.STABLE); 309 assume().that(graph.allowsSelfLoops()).isTrue(); 310 311 putEdge(2, 1); 312 putEdge(1, 1); 313 putEdge(1, 3); 314 putEdge(1, 2); 315 316 assertThat(graph.incidentEdges(1)) 317 .containsExactly( 318 EndpointPair.ordered(2, 1), 319 EndpointPair.ordered(1, 1), 320 EndpointPair.ordered(1, 3), 321 EndpointPair.ordered(1, 2)) 322 .inOrder(); 323 } 324 325 /** 326 * Populates the graph with nodes and edges in a star shape with node `1` in the middle. 327 * 328 * <p>Note that the edges are added in a shuffled order to properly test the effect of the 329 * insertion order. 330 */ populateStarShapedGraph()331 private void populateStarShapedGraph() { 332 putEdge(2, 1); 333 putEdge(1, 4); 334 putEdge(1, 3); 335 putEdge(5, 1); 336 putEdge(1, 2); 337 putEdge(3, 1); 338 } 339 340 // Element Mutation 341 342 @Test putEdge_existingNodes()343 public void putEdge_existingNodes() { 344 assume().that(graphIsMutable()).isTrue(); 345 346 // Adding nodes initially for safety (insulating from possible future 347 // modifications to proxy methods) 348 addNode(N1); 349 addNode(N2); 350 351 assertThat(graphAsMutableGraph.putEdge(N1, N2)).isTrue(); 352 } 353 354 @Test putEdge_existingEdgeBetweenSameNodes()355 public void putEdge_existingEdgeBetweenSameNodes() { 356 assume().that(graphIsMutable()).isTrue(); 357 358 assertThat(graphAsMutableGraph.putEdge(N1, N2)).isTrue(); 359 assertThat(graphAsMutableGraph.putEdge(N1, N2)).isFalse(); 360 } 361 362 @Test putEdge_orderMismatch()363 public void putEdge_orderMismatch() { 364 assume().that(graphIsMutable()).isTrue(); 365 366 EndpointPair<Integer> endpoints = EndpointPair.unordered(N1, N2); 367 try { 368 graphAsMutableGraph.putEdge(endpoints); 369 fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH); 370 } catch (IllegalArgumentException e) { 371 assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH); 372 } 373 } 374 375 /** 376 * Tests that the method {@code putEdge} will silently add the missing nodes to the graph, then 377 * add the edge connecting them. We are not using the proxy methods here as we want to test {@code 378 * putEdge} when the end-points are not elements of the graph. 379 */ 380 @Test putEdge_nodesNotInGraph()381 public void putEdge_nodesNotInGraph() { 382 assume().that(graphIsMutable()).isTrue(); 383 384 graphAsMutableGraph.addNode(N1); 385 assertTrue(graphAsMutableGraph.putEdge(N1, N5)); 386 assertTrue(graphAsMutableGraph.putEdge(N4, N1)); 387 assertTrue(graphAsMutableGraph.putEdge(N2, N3)); 388 assertThat(graph.nodes()).containsExactly(N1, N5, N4, N2, N3).inOrder(); 389 assertThat(graph.successors(N1)).containsExactly(N5); 390 assertThat(graph.successors(N2)).containsExactly(N3); 391 assertThat(graph.successors(N3)).isEmpty(); 392 assertThat(graph.successors(N4)).containsExactly(N1); 393 assertThat(graph.successors(N5)).isEmpty(); 394 } 395 396 @Test putEdge_doesntAllowSelfLoops()397 public void putEdge_doesntAllowSelfLoops() { 398 assume().that(graphIsMutable()).isTrue(); 399 assume().that(graph.allowsSelfLoops()).isFalse(); 400 401 try { 402 graphAsMutableGraph.putEdge(N1, N1); 403 fail(ERROR_ADDED_SELF_LOOP); 404 } catch (IllegalArgumentException e) { 405 assertThat(e).hasMessageThat().contains(ERROR_SELF_LOOP); 406 } 407 } 408 409 @Test putEdge_allowsSelfLoops()410 public void putEdge_allowsSelfLoops() { 411 assume().that(graphIsMutable()).isTrue(); 412 assume().that(graph.allowsSelfLoops()).isTrue(); 413 414 assertThat(graphAsMutableGraph.putEdge(N1, N1)).isTrue(); 415 assertThat(graph.successors(N1)).containsExactly(N1); 416 assertThat(graph.predecessors(N1)).containsExactly(N1); 417 } 418 419 @Test putEdge_existingSelfLoopEdgeBetweenSameNodes()420 public void putEdge_existingSelfLoopEdgeBetweenSameNodes() { 421 assume().that(graphIsMutable()).isTrue(); 422 assume().that(graph.allowsSelfLoops()).isTrue(); 423 424 graphAsMutableGraph.putEdge(N1, N1); 425 assertThat(graphAsMutableGraph.putEdge(N1, N1)).isFalse(); 426 } 427 428 @Test removeEdge_antiparallelEdges()429 public void removeEdge_antiparallelEdges() { 430 assume().that(graphIsMutable()).isTrue(); 431 432 putEdge(N1, N2); 433 putEdge(N2, N1); 434 435 assertThat(graphAsMutableGraph.removeEdge(N1, N2)).isTrue(); 436 assertThat(graph.successors(N1)).isEmpty(); 437 assertThat(graph.predecessors(N1)).containsExactly(N2); 438 assertThat(graph.edges()).hasSize(1); 439 440 assertThat(graphAsMutableGraph.removeEdge(N2, N1)).isTrue(); 441 assertThat(graph.successors(N1)).isEmpty(); 442 assertThat(graph.predecessors(N1)).isEmpty(); 443 assertThat(graph.edges()).isEmpty(); 444 } 445 446 @Test removeEdge_orderMismatch()447 public void removeEdge_orderMismatch() { 448 assume().that(graphIsMutable()).isTrue(); 449 450 putEdge(N1, N2); 451 EndpointPair<Integer> endpoints = EndpointPair.unordered(N1, N2); 452 try { 453 graphAsMutableGraph.removeEdge(endpoints); 454 fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH); 455 } catch (IllegalArgumentException e) { 456 assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH); 457 } 458 } 459 460 @Test removeNode_existingNodeWithSelfLoopEdge()461 public void removeNode_existingNodeWithSelfLoopEdge() { 462 assume().that(graphIsMutable()).isTrue(); 463 assume().that(graph.allowsSelfLoops()).isTrue(); 464 465 addNode(N1); 466 putEdge(N1, N1); 467 assertThat(graphAsMutableGraph.removeNode(N1)).isTrue(); 468 assertThat(graph.nodes()).isEmpty(); 469 } 470 471 @Test removeEdge_existingSelfLoopEdge()472 public void removeEdge_existingSelfLoopEdge() { 473 assume().that(graphIsMutable()).isTrue(); 474 assume().that(graph.allowsSelfLoops()).isTrue(); 475 476 putEdge(N1, N1); 477 assertThat(graphAsMutableGraph.removeEdge(N1, N1)).isTrue(); 478 assertThat(graph.nodes()).containsExactly(N1); 479 assertThat(graph.successors(N1)).isEmpty(); 480 } 481 } 482