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