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