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