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.TestUtil.ERROR_NODE_NOT_IN_GRAPH; 20 import static com.google.common.graph.TestUtil.assertEdgeNotInGraphErrorMessage; 21 import static com.google.common.graph.TestUtil.assertNodeNotInGraphErrorMessage; 22 import static com.google.common.graph.TestUtil.assertStronglyEquivalent; 23 import static com.google.common.graph.TestUtil.sanityCheckSet; 24 import static com.google.common.truth.Truth.assertThat; 25 import static org.junit.Assert.assertFalse; 26 import static org.junit.Assert.assertTrue; 27 import static org.junit.Assert.fail; 28 29 import com.google.common.collect.ImmutableSet; 30 import com.google.common.collect.Sets; 31 import com.google.errorprone.annotations.CanIgnoreReturnValue; 32 import java.util.Set; 33 import org.junit.After; 34 import org.junit.Before; 35 import org.junit.Test; 36 37 /** 38 * Abstract base class for testing implementations of {@link Network} interface. Network instances 39 * created for testing should have Integer node and String edge objects. 40 * 41 * <p>Test cases that should be handled similarly in any graph implementation are included in this 42 * class. For example, testing that {@code nodes()} method returns the set of the nodes in the 43 * graph. The following test cases are left for the subclasses to handle: 44 * 45 * <ul> 46 * <li>Test cases related to whether the graph is directed, undirected, mutable, or immutable. 47 * <li>Test cases related to the specific implementation of the {@link Network} interface. 48 * </ul> 49 * 50 * TODO(user): Make this class generic (using <N, E>) for all node and edge types. 51 * TODO(user): Differentiate between directed and undirected edge strings. 52 */ 53 public abstract class AbstractNetworkTest { 54 MutableNetwork<Integer, String> network; 55 static final Integer N1 = 1; 56 static final Integer N2 = 2; 57 static final Integer N3 = 3; 58 static final Integer N4 = 4; 59 static final Integer N5 = 5; 60 static final Integer NODE_NOT_IN_GRAPH = 1000; 61 62 static final String E11 = "1-1"; 63 static final String E11_A = "1-1a"; 64 static final String E12 = "1-2"; 65 static final String E12_A = "1-2a"; 66 static final String E12_B = "1-2b"; 67 static final String E21 = "2-1"; 68 static final String E13 = "1-3"; 69 static final String E14 = "1-4"; 70 static final String E23 = "2-3"; 71 static final String E31 = "3-1"; 72 static final String E34 = "3-4"; 73 static final String E41 = "4-1"; 74 static final String E15 = "1-5"; 75 static final String EDGE_NOT_IN_GRAPH = "edgeNotInGraph"; 76 77 // TODO(user): Consider separating Strings that we've defined here to capture 78 // identifiable substrings of expected error messages, from Strings that we've defined 79 // here to provide error messages. 80 // TODO(user): Some Strings used in the subclasses can be added as static Strings 81 // here too. 82 static final String ERROR_PARALLEL_EDGE = "connected by a different edge"; 83 static final String ERROR_REUSE_EDGE = "it cannot be reused to connect"; 84 static final String ERROR_MODIFIABLE_COLLECTION = 85 "Collection returned is unexpectedly modifiable"; 86 static final String ERROR_SELF_LOOP = "self-loops are not allowed"; 87 static final String ERROR_EDGE_NOT_IN_GRAPH = 88 "Should not be allowed to pass an edge that is not an element of the graph."; 89 static final String ERROR_ADDED_SELF_LOOP = "Should not be allowed to add a self-loop edge."; 90 static final String ERROR_ADDED_PARALLEL_EDGE = "Should not be allowed to add a parallel edge."; 91 static final String ERROR_ADDED_EXISTING_EDGE = 92 "Reusing an existing edge to connect different nodes succeeded"; 93 94 /** Creates and returns an instance of the graph to be tested. */ createGraph()95 public abstract MutableNetwork<Integer, String> createGraph(); 96 97 /** 98 * A proxy method that adds the node {@code n} to the graph being tested. In case of Immutable 99 * graph implementations, this method should add {@code n} to the graph builder and build a new 100 * graph with the current builder state. 101 * 102 * @return {@code true} iff the graph was modified as a result of this call 103 */ 104 @CanIgnoreReturnValue addNode(Integer n)105 protected boolean addNode(Integer n) { 106 return network.addNode(n); 107 } 108 109 /** 110 * A proxy method that adds the edge {@code e} to the graph being tested. In case of Immutable 111 * graph implementations, this method should add {@code e} to the graph builder and build a new 112 * graph with the current builder state. 113 * 114 * <p>This method should be used in tests of specific implementations if you want to ensure 115 * uniform behavior (including side effects) with how edges are added elsewhere in the tests. For 116 * example, the existing implementations of this method explicitly add the supplied nodes to the 117 * graph, and then call {@code graph.addEdge()} to connect the edge to the nodes; this is not part 118 * of the contract of {@code graph.addEdge()} and is done for convenience. In cases where you want 119 * to avoid such side effects (e.g., if you're testing what happens in your implementation if you 120 * add an edge whose end-points don't already exist in the graph), you should <b>not</b> use this 121 * method. 122 * 123 * <p>TODO(user): remove the addNode() calls, that's now contractually guaranteed 124 * 125 * @return {@code true} iff the graph was modified as a result of this call 126 */ 127 @CanIgnoreReturnValue addEdge(Integer n1, Integer n2, String e)128 protected boolean addEdge(Integer n1, Integer n2, String e) { 129 network.addNode(n1); 130 network.addNode(n2); 131 return network.addEdge(n1, n2, e); 132 } 133 addEdge(EndpointPair<Integer> endpoints, String e)134 protected boolean addEdge(EndpointPair<Integer> endpoints, String e) { 135 network.addNode(endpoints.nodeU()); 136 network.addNode(endpoints.nodeV()); 137 return network.addEdge(endpoints, e); 138 } 139 140 @Before init()141 public void init() { 142 network = createGraph(); 143 } 144 145 @After validateNetworkState()146 public void validateNetworkState() { 147 validateNetwork(network); 148 } 149 validateNetwork(Network<N, E> network)150 static <N, E> void validateNetwork(Network<N, E> network) { 151 assertStronglyEquivalent(network, Graphs.copyOf(network)); 152 assertStronglyEquivalent(network, ImmutableNetwork.copyOf(network)); 153 154 String networkString = network.toString(); 155 assertThat(networkString).contains("isDirected: " + network.isDirected()); 156 assertThat(networkString).contains("allowsParallelEdges: " + network.allowsParallelEdges()); 157 assertThat(networkString).contains("allowsSelfLoops: " + network.allowsSelfLoops()); 158 159 int nodeStart = networkString.indexOf("nodes:"); 160 int edgeStart = networkString.indexOf("edges:"); 161 String nodeString = networkString.substring(nodeStart, edgeStart); 162 String edgeString = networkString.substring(edgeStart); 163 164 Graph<N> asGraph = network.asGraph(); 165 AbstractGraphTest.validateGraph(asGraph); 166 assertThat(network.nodes()).isEqualTo(asGraph.nodes()); 167 assertThat(network.edges().size()).isAtLeast(asGraph.edges().size()); 168 assertThat(network.nodeOrder()).isEqualTo(asGraph.nodeOrder()); 169 assertThat(network.isDirected()).isEqualTo(asGraph.isDirected()); 170 assertThat(network.allowsSelfLoops()).isEqualTo(asGraph.allowsSelfLoops()); 171 172 for (E edge : sanityCheckSet(network.edges())) { 173 // TODO(b/27817069): Consider verifying the edge's incident nodes in the string. 174 assertThat(edgeString).contains(edge.toString()); 175 176 EndpointPair<N> endpointPair = network.incidentNodes(edge); 177 N nodeU = endpointPair.nodeU(); 178 N nodeV = endpointPair.nodeV(); 179 assertThat(asGraph.edges()).contains(EndpointPair.of(network, nodeU, nodeV)); 180 assertThat(network.edgesConnecting(nodeU, nodeV)).contains(edge); 181 assertThat(network.successors(nodeU)).contains(nodeV); 182 assertThat(network.adjacentNodes(nodeU)).contains(nodeV); 183 assertThat(network.outEdges(nodeU)).contains(edge); 184 assertThat(network.incidentEdges(nodeU)).contains(edge); 185 assertThat(network.predecessors(nodeV)).contains(nodeU); 186 assertThat(network.adjacentNodes(nodeV)).contains(nodeU); 187 assertThat(network.inEdges(nodeV)).contains(edge); 188 assertThat(network.incidentEdges(nodeV)).contains(edge); 189 190 for (N incidentNode : network.incidentNodes(edge)) { 191 assertThat(network.nodes()).contains(incidentNode); 192 for (E adjacentEdge : network.incidentEdges(incidentNode)) { 193 assertTrue( 194 edge.equals(adjacentEdge) || network.adjacentEdges(edge).contains(adjacentEdge)); 195 } 196 } 197 } 198 199 for (N node : sanityCheckSet(network.nodes())) { 200 assertThat(nodeString).contains(node.toString()); 201 202 assertThat(network.adjacentNodes(node)).isEqualTo(asGraph.adjacentNodes(node)); 203 assertThat(network.predecessors(node)).isEqualTo(asGraph.predecessors(node)); 204 assertThat(network.successors(node)).isEqualTo(asGraph.successors(node)); 205 206 int selfLoopCount = network.edgesConnecting(node, node).size(); 207 assertThat(network.incidentEdges(node).size() + selfLoopCount) 208 .isEqualTo(network.degree(node)); 209 210 if (network.isDirected()) { 211 assertThat(network.incidentEdges(node).size() + selfLoopCount) 212 .isEqualTo(network.inDegree(node) + network.outDegree(node)); 213 assertThat(network.inEdges(node)).hasSize(network.inDegree(node)); 214 assertThat(network.outEdges(node)).hasSize(network.outDegree(node)); 215 } else { 216 assertThat(network.predecessors(node)).isEqualTo(network.adjacentNodes(node)); 217 assertThat(network.successors(node)).isEqualTo(network.adjacentNodes(node)); 218 assertThat(network.inEdges(node)).isEqualTo(network.incidentEdges(node)); 219 assertThat(network.outEdges(node)).isEqualTo(network.incidentEdges(node)); 220 assertThat(network.inDegree(node)).isEqualTo(network.degree(node)); 221 assertThat(network.outDegree(node)).isEqualTo(network.degree(node)); 222 } 223 224 for (N otherNode : network.nodes()) { 225 Set<E> edgesConnecting = sanityCheckSet(network.edgesConnecting(node, otherNode)); 226 switch (edgesConnecting.size()) { 227 case 0: 228 assertThat(network.edgeConnectingOrNull(node, otherNode)).isNull(); 229 assertThat(network.edgeConnecting(node, otherNode).isPresent()).isFalse(); 230 assertThat(network.hasEdgeConnecting(node, otherNode)).isFalse(); 231 break; 232 case 1: 233 E edge = edgesConnecting.iterator().next(); 234 assertThat(network.edgeConnectingOrNull(node, otherNode)).isEqualTo(edge); 235 assertThat(network.edgeConnecting(node, otherNode).get()).isEqualTo(edge); 236 assertThat(network.hasEdgeConnecting(node, otherNode)).isTrue(); 237 break; 238 default: 239 assertThat(network.hasEdgeConnecting(node, otherNode)).isTrue(); 240 try { 241 network.edgeConnectingOrNull(node, otherNode); 242 fail(); 243 } catch (IllegalArgumentException expected) { 244 } 245 try { 246 network.edgeConnecting(node, otherNode); 247 fail(); 248 } catch (IllegalArgumentException expected) { 249 } 250 } 251 252 boolean isSelfLoop = node.equals(otherNode); 253 boolean connected = !edgesConnecting.isEmpty(); 254 if (network.isDirected() || !isSelfLoop) { 255 assertThat(edgesConnecting) 256 .isEqualTo(Sets.intersection(network.outEdges(node), network.inEdges(otherNode))); 257 } 258 if (!network.allowsParallelEdges()) { 259 assertThat(edgesConnecting.size()).isAtMost(1); 260 } 261 if (!network.allowsSelfLoops() && isSelfLoop) { 262 assertThat(connected).isFalse(); 263 } 264 265 assertThat(network.successors(node).contains(otherNode)).isEqualTo(connected); 266 assertThat(network.predecessors(otherNode).contains(node)).isEqualTo(connected); 267 for (E edge : edgesConnecting) { 268 assertThat(network.incidentNodes(edge)) 269 .isEqualTo(EndpointPair.of(network, node, otherNode)); 270 assertThat(network.outEdges(node)).contains(edge); 271 assertThat(network.inEdges(otherNode)).contains(edge); 272 } 273 } 274 275 for (N adjacentNode : sanityCheckSet(network.adjacentNodes(node))) { 276 assertTrue( 277 network.predecessors(node).contains(adjacentNode) 278 || network.successors(node).contains(adjacentNode)); 279 assertTrue( 280 !network.edgesConnecting(node, adjacentNode).isEmpty() 281 || !network.edgesConnecting(adjacentNode, node).isEmpty()); 282 } 283 284 for (N predecessor : sanityCheckSet(network.predecessors(node))) { 285 assertThat(network.successors(predecessor)).contains(node); 286 assertThat(network.edgesConnecting(predecessor, node)).isNotEmpty(); 287 } 288 289 for (N successor : sanityCheckSet(network.successors(node))) { 290 assertThat(network.predecessors(successor)).contains(node); 291 assertThat(network.edgesConnecting(node, successor)).isNotEmpty(); 292 } 293 294 for (E incidentEdge : sanityCheckSet(network.incidentEdges(node))) { 295 assertTrue( 296 network.inEdges(node).contains(incidentEdge) 297 || network.outEdges(node).contains(incidentEdge)); 298 assertThat(network.edges()).contains(incidentEdge); 299 assertThat(network.incidentNodes(incidentEdge)).contains(node); 300 } 301 302 for (E inEdge : sanityCheckSet(network.inEdges(node))) { 303 assertThat(network.incidentEdges(node)).contains(inEdge); 304 assertThat(network.outEdges(network.incidentNodes(inEdge).adjacentNode(node))) 305 .contains(inEdge); 306 if (network.isDirected()) { 307 assertThat(network.incidentNodes(inEdge).target()).isEqualTo(node); 308 } 309 } 310 311 for (E outEdge : sanityCheckSet(network.outEdges(node))) { 312 assertThat(network.incidentEdges(node)).contains(outEdge); 313 assertThat(network.inEdges(network.incidentNodes(outEdge).adjacentNode(node))) 314 .contains(outEdge); 315 if (network.isDirected()) { 316 assertThat(network.incidentNodes(outEdge).source()).isEqualTo(node); 317 } 318 } 319 } 320 } 321 322 /** 323 * Verifies that the {@code Set} returned by {@code nodes} has the expected mutability property 324 * (see the {@code Network} documentation for more information). 325 */ 326 @Test nodes_checkReturnedSetMutability()327 public abstract void nodes_checkReturnedSetMutability(); 328 329 /** 330 * Verifies that the {@code Set} returned by {@code edges} has the expected mutability property 331 * (see the {@code Network} documentation for more information). 332 */ 333 @Test edges_checkReturnedSetMutability()334 public abstract void edges_checkReturnedSetMutability(); 335 336 /** 337 * Verifies that the {@code Set} returned by {@code incidentEdges} has the expected mutability 338 * property (see the {@code Network} documentation for more information). 339 */ 340 @Test incidentEdges_checkReturnedSetMutability()341 public abstract void incidentEdges_checkReturnedSetMutability(); 342 343 /** 344 * Verifies that the {@code Set} returned by {@code adjacentNodes} has the expected mutability 345 * property (see the {@code Network} documentation for more information). 346 */ 347 @Test adjacentNodes_checkReturnedSetMutability()348 public abstract void adjacentNodes_checkReturnedSetMutability(); 349 350 /** 351 * Verifies that the {@code Set} returned by {@code adjacentEdges} has the expected mutability 352 * property (see the {@code Network} documentation for more information). 353 */ 354 @Test adjacentEdges_checkReturnedSetMutability()355 public abstract void adjacentEdges_checkReturnedSetMutability(); 356 357 /** 358 * Verifies that the {@code Set} returned by {@code edgesConnecting} has the expected mutability 359 * property (see the {@code Network} documentation for more information). 360 */ 361 @Test edgesConnecting_checkReturnedSetMutability()362 public abstract void edgesConnecting_checkReturnedSetMutability(); 363 364 /** 365 * Verifies that the {@code Set} returned by {@code inEdges} has the expected mutability property 366 * (see the {@code Network} documentation for more information). 367 */ 368 @Test inEdges_checkReturnedSetMutability()369 public abstract void inEdges_checkReturnedSetMutability(); 370 371 /** 372 * Verifies that the {@code Set} returned by {@code outEdges} has the expected mutability property 373 * (see the {@code Network} documentation for more information). 374 */ 375 @Test outEdges_checkReturnedSetMutability()376 public abstract void outEdges_checkReturnedSetMutability(); 377 378 /** 379 * Verifies that the {@code Set} returned by {@code predecessors} has the expected mutability 380 * property (see the {@code Network} documentation for more information). 381 */ 382 @Test predecessors_checkReturnedSetMutability()383 public abstract void predecessors_checkReturnedSetMutability(); 384 385 /** 386 * Verifies that the {@code Set} returned by {@code successors} has the expected mutability 387 * property (see the {@code Network} documentation for more information). 388 */ 389 @Test successors_checkReturnedSetMutability()390 public abstract void successors_checkReturnedSetMutability(); 391 392 @Test nodes_oneNode()393 public void nodes_oneNode() { 394 addNode(N1); 395 assertThat(network.nodes()).containsExactly(N1); 396 } 397 398 @Test nodes_noNodes()399 public void nodes_noNodes() { 400 assertThat(network.nodes()).isEmpty(); 401 } 402 403 @Test edges_oneEdge()404 public void edges_oneEdge() { 405 addEdge(N1, N2, E12); 406 assertThat(network.edges()).containsExactly(E12); 407 } 408 409 @Test edges_noEdges()410 public void edges_noEdges() { 411 assertThat(network.edges()).isEmpty(); 412 // Network with no edges, given disconnected nodes 413 addNode(N1); 414 addNode(N2); 415 assertThat(network.edges()).isEmpty(); 416 } 417 418 @Test incidentEdges_oneEdge()419 public void incidentEdges_oneEdge() { 420 addEdge(N1, N2, E12); 421 assertThat(network.incidentEdges(N2)).containsExactly(E12); 422 assertThat(network.incidentEdges(N1)).containsExactly(E12); 423 } 424 425 @Test incidentEdges_isolatedNode()426 public void incidentEdges_isolatedNode() { 427 addNode(N1); 428 assertThat(network.incidentEdges(N1)).isEmpty(); 429 } 430 431 @Test incidentEdges_nodeNotInGraph()432 public void incidentEdges_nodeNotInGraph() { 433 try { 434 network.incidentEdges(NODE_NOT_IN_GRAPH); 435 fail(ERROR_NODE_NOT_IN_GRAPH); 436 } catch (IllegalArgumentException e) { 437 assertNodeNotInGraphErrorMessage(e); 438 } 439 } 440 441 @Test incidentNodes_oneEdge()442 public void incidentNodes_oneEdge() { 443 addEdge(N1, N2, E12); 444 assertThat(network.incidentNodes(E12)).containsExactly(N1, N2); 445 } 446 447 @Test incidentNodes_edgeNotInGraph()448 public void incidentNodes_edgeNotInGraph() { 449 try { 450 network.incidentNodes(EDGE_NOT_IN_GRAPH); 451 fail(ERROR_EDGE_NOT_IN_GRAPH); 452 } catch (IllegalArgumentException e) { 453 assertEdgeNotInGraphErrorMessage(e); 454 } 455 } 456 457 @Test adjacentNodes_oneEdge()458 public void adjacentNodes_oneEdge() { 459 addEdge(N1, N2, E12); 460 assertThat(network.adjacentNodes(N1)).containsExactly(N2); 461 assertThat(network.adjacentNodes(N2)).containsExactly(N1); 462 } 463 464 @Test adjacentNodes_noAdjacentNodes()465 public void adjacentNodes_noAdjacentNodes() { 466 addNode(N1); 467 assertThat(network.adjacentNodes(N1)).isEmpty(); 468 } 469 470 @Test adjacentNodes_nodeNotInGraph()471 public void adjacentNodes_nodeNotInGraph() { 472 try { 473 network.adjacentNodes(NODE_NOT_IN_GRAPH); 474 fail(ERROR_NODE_NOT_IN_GRAPH); 475 } catch (IllegalArgumentException e) { 476 assertNodeNotInGraphErrorMessage(e); 477 } 478 } 479 480 @Test adjacentEdges_bothEndpoints()481 public void adjacentEdges_bothEndpoints() { 482 addEdge(N1, N2, E12); 483 addEdge(N2, N3, E23); 484 addEdge(N3, N1, E31); 485 addEdge(N3, N4, E34); 486 assertThat(network.adjacentEdges(E12)).containsExactly(E31, E23); 487 } 488 489 @Test adjacentEdges_noAdjacentEdges()490 public void adjacentEdges_noAdjacentEdges() { 491 addEdge(N1, N2, E12); 492 addEdge(N3, N4, E34); 493 assertThat(network.adjacentEdges(E12)).isEmpty(); 494 } 495 496 @Test adjacentEdges_edgeNotInGraph()497 public void adjacentEdges_edgeNotInGraph() { 498 try { 499 network.adjacentEdges(EDGE_NOT_IN_GRAPH); 500 fail(ERROR_EDGE_NOT_IN_GRAPH); 501 } catch (IllegalArgumentException e) { 502 assertEdgeNotInGraphErrorMessage(e); 503 } 504 } 505 506 @Test edgesConnecting_disconnectedNodes()507 public void edgesConnecting_disconnectedNodes() { 508 addNode(N1); 509 addNode(N2); 510 assertThat(network.edgesConnecting(N1, N2)).isEmpty(); 511 } 512 513 @Test edgesConnecting_nodesNotInGraph()514 public void edgesConnecting_nodesNotInGraph() { 515 addNode(N1); 516 addNode(N2); 517 try { 518 network.edgesConnecting(N1, NODE_NOT_IN_GRAPH); 519 fail(ERROR_NODE_NOT_IN_GRAPH); 520 } catch (IllegalArgumentException e) { 521 assertNodeNotInGraphErrorMessage(e); 522 } 523 try { 524 network.edgesConnecting(NODE_NOT_IN_GRAPH, N2); 525 fail(ERROR_NODE_NOT_IN_GRAPH); 526 } catch (IllegalArgumentException e) { 527 assertNodeNotInGraphErrorMessage(e); 528 } 529 try { 530 network.edgesConnecting(NODE_NOT_IN_GRAPH, NODE_NOT_IN_GRAPH); 531 fail(ERROR_NODE_NOT_IN_GRAPH); 532 } catch (IllegalArgumentException e) { 533 assertNodeNotInGraphErrorMessage(e); 534 } 535 } 536 537 @Test inEdges_noInEdges()538 public void inEdges_noInEdges() { 539 addNode(N1); 540 assertThat(network.inEdges(N1)).isEmpty(); 541 } 542 543 @Test inEdges_nodeNotInGraph()544 public void inEdges_nodeNotInGraph() { 545 try { 546 network.inEdges(NODE_NOT_IN_GRAPH); 547 fail(ERROR_NODE_NOT_IN_GRAPH); 548 } catch (IllegalArgumentException e) { 549 assertNodeNotInGraphErrorMessage(e); 550 } 551 } 552 553 @Test outEdges_noOutEdges()554 public void outEdges_noOutEdges() { 555 addNode(N1); 556 assertThat(network.outEdges(N1)).isEmpty(); 557 } 558 559 @Test outEdges_nodeNotInGraph()560 public void outEdges_nodeNotInGraph() { 561 try { 562 network.outEdges(NODE_NOT_IN_GRAPH); 563 fail(ERROR_NODE_NOT_IN_GRAPH); 564 } catch (IllegalArgumentException e) { 565 assertNodeNotInGraphErrorMessage(e); 566 } 567 } 568 569 @Test predecessors_noPredecessors()570 public void predecessors_noPredecessors() { 571 addNode(N1); 572 assertThat(network.predecessors(N1)).isEmpty(); 573 } 574 575 @Test predecessors_nodeNotInGraph()576 public void predecessors_nodeNotInGraph() { 577 try { 578 network.predecessors(NODE_NOT_IN_GRAPH); 579 fail(ERROR_NODE_NOT_IN_GRAPH); 580 } catch (IllegalArgumentException e) { 581 assertNodeNotInGraphErrorMessage(e); 582 } 583 } 584 585 @Test successors_noSuccessors()586 public void successors_noSuccessors() { 587 addNode(N1); 588 assertThat(network.successors(N1)).isEmpty(); 589 } 590 591 @Test successors_nodeNotInGraph()592 public void successors_nodeNotInGraph() { 593 try { 594 network.successors(NODE_NOT_IN_GRAPH); 595 fail(ERROR_NODE_NOT_IN_GRAPH); 596 } catch (IllegalArgumentException e) { 597 assertNodeNotInGraphErrorMessage(e); 598 } 599 } 600 601 @Test addNode_newNode()602 public void addNode_newNode() { 603 assertTrue(addNode(N1)); 604 assertThat(network.nodes()).contains(N1); 605 } 606 607 @Test addNode_existingNode()608 public void addNode_existingNode() { 609 addNode(N1); 610 ImmutableSet<Integer> nodes = ImmutableSet.copyOf(network.nodes()); 611 assertFalse(addNode(N1)); 612 assertThat(network.nodes()).containsExactlyElementsIn(nodes); 613 } 614 615 @Test removeNode_existingNode()616 public void removeNode_existingNode() { 617 addEdge(N1, N2, E12); 618 addEdge(N4, N1, E41); 619 assertTrue(network.removeNode(N1)); 620 assertFalse(network.removeNode(N1)); 621 assertThat(network.nodes()).containsExactly(N2, N4); 622 assertThat(network.edges()).doesNotContain(E12); 623 assertThat(network.edges()).doesNotContain(E41); 624 } 625 626 @Test removeNode_nodeNotPresent()627 public void removeNode_nodeNotPresent() { 628 addNode(N1); 629 ImmutableSet<Integer> nodes = ImmutableSet.copyOf(network.nodes()); 630 assertFalse(network.removeNode(NODE_NOT_IN_GRAPH)); 631 assertThat(network.nodes()).containsExactlyElementsIn(nodes); 632 } 633 634 @Test removeNode_queryAfterRemoval()635 public void removeNode_queryAfterRemoval() { 636 addNode(N1); 637 @SuppressWarnings("unused") 638 Set<Integer> unused = network.adjacentNodes(N1); // ensure cache (if any) is populated 639 assertTrue(network.removeNode(N1)); 640 try { 641 network.adjacentNodes(N1); 642 fail(ERROR_NODE_NOT_IN_GRAPH); 643 } catch (IllegalArgumentException e) { 644 assertNodeNotInGraphErrorMessage(e); 645 } 646 } 647 648 @Test removeEdge_existingEdge()649 public void removeEdge_existingEdge() { 650 addEdge(N1, N2, E12); 651 assertTrue(network.removeEdge(E12)); 652 assertFalse(network.removeEdge(E12)); 653 assertThat(network.edges()).doesNotContain(E12); 654 assertThat(network.edgesConnecting(N1, N2)).isEmpty(); 655 } 656 657 @Test removeEdge_oneOfMany()658 public void removeEdge_oneOfMany() { 659 addEdge(N1, N2, E12); 660 addEdge(N1, N3, E13); 661 addEdge(N1, N4, E14); 662 assertThat(network.edges()).containsExactly(E12, E13, E14); 663 assertTrue(network.removeEdge(E13)); 664 assertThat(network.edges()).containsExactly(E12, E14); 665 } 666 667 @Test removeEdge_edgeNotPresent()668 public void removeEdge_edgeNotPresent() { 669 addEdge(N1, N2, E12); 670 ImmutableSet<String> edges = ImmutableSet.copyOf(network.edges()); 671 assertFalse(network.removeEdge(EDGE_NOT_IN_GRAPH)); 672 assertThat(network.edges()).containsExactlyElementsIn(edges); 673 } 674 675 @Test removeEdge_queryAfterRemoval()676 public void removeEdge_queryAfterRemoval() { 677 addEdge(N1, N2, E12); 678 @SuppressWarnings("unused") 679 EndpointPair<Integer> unused = network.incidentNodes(E12); // ensure cache (if any) is populated 680 assertTrue(network.removeEdge(E12)); 681 try { 682 network.incidentNodes(E12); 683 fail(ERROR_EDGE_NOT_IN_GRAPH); 684 } catch (IllegalArgumentException e) { 685 assertEdgeNotInGraphErrorMessage(e); 686 } 687 } 688 } 689