1 /* 2 * Copyright (C) 2016 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.graph.TestUtil.assertStronglyEquivalent; 21 import static com.google.common.truth.Truth.assertThat; 22 import static java.util.concurrent.Executors.newFixedThreadPool; 23 import static org.junit.Assert.fail; 24 25 import com.google.common.collect.ImmutableList; 26 import java.util.Set; 27 import java.util.concurrent.Callable; 28 import java.util.concurrent.CyclicBarrier; 29 import java.util.concurrent.ExecutorService; 30 import java.util.concurrent.Future; 31 import org.junit.After; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 import org.junit.runners.JUnit4; 35 36 /** Tests for {@link StandardMutableValueGraph} and related functionality. */ 37 // TODO(user): Expand coverage and move to proper test suite. 38 @RunWith(JUnit4.class) 39 public final class ValueGraphTest { 40 private static final String DEFAULT = "default"; 41 42 MutableValueGraph<Integer, String> graph; 43 44 @After validateGraphState()45 public void validateGraphState() { 46 assertStronglyEquivalent(graph, Graphs.copyOf(graph)); 47 assertStronglyEquivalent(graph, ImmutableValueGraph.copyOf(graph)); 48 49 Graph<Integer> asGraph = graph.asGraph(); 50 AbstractGraphTest.validateGraph(asGraph); 51 assertThat(graph.nodes()).isEqualTo(asGraph.nodes()); 52 assertThat(graph.edges()).isEqualTo(asGraph.edges()); 53 assertThat(graph.nodeOrder()).isEqualTo(asGraph.nodeOrder()); 54 assertThat(graph.incidentEdgeOrder()).isEqualTo(asGraph.incidentEdgeOrder()); 55 assertThat(graph.isDirected()).isEqualTo(asGraph.isDirected()); 56 assertThat(graph.allowsSelfLoops()).isEqualTo(asGraph.allowsSelfLoops()); 57 58 for (Integer node : graph.nodes()) { 59 assertThat(graph.adjacentNodes(node)).isEqualTo(asGraph.adjacentNodes(node)); 60 assertThat(graph.predecessors(node)).isEqualTo(asGraph.predecessors(node)); 61 assertThat(graph.successors(node)).isEqualTo(asGraph.successors(node)); 62 assertThat(graph.degree(node)).isEqualTo(asGraph.degree(node)); 63 assertThat(graph.inDegree(node)).isEqualTo(asGraph.inDegree(node)); 64 assertThat(graph.outDegree(node)).isEqualTo(asGraph.outDegree(node)); 65 66 for (Integer otherNode : graph.nodes()) { 67 boolean hasEdge = graph.hasEdgeConnecting(node, otherNode); 68 assertThat(hasEdge).isEqualTo(asGraph.hasEdgeConnecting(node, otherNode)); 69 assertThat(graph.edgeValueOrDefault(node, otherNode, null) != null).isEqualTo(hasEdge); 70 assertThat(!graph.edgeValueOrDefault(node, otherNode, DEFAULT).equals(DEFAULT)) 71 .isEqualTo(hasEdge); 72 } 73 } 74 } 75 76 @Test directedGraph()77 public void directedGraph() { 78 graph = ValueGraphBuilder.directed().allowsSelfLoops(true).build(); 79 graph.putEdgeValue(1, 2, "valueA"); 80 graph.putEdgeValue(2, 1, "valueB"); 81 graph.putEdgeValue(2, 3, "valueC"); 82 graph.putEdgeValue(4, 4, "valueD"); 83 84 assertThat(graph.edgeValueOrDefault(1, 2, null)).isEqualTo("valueA"); 85 assertThat(graph.edgeValueOrDefault(2, 1, null)).isEqualTo("valueB"); 86 assertThat(graph.edgeValueOrDefault(2, 3, null)).isEqualTo("valueC"); 87 assertThat(graph.edgeValueOrDefault(4, 4, null)).isEqualTo("valueD"); 88 assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo("valueA"); 89 assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo("valueB"); 90 assertThat(graph.edgeValueOrDefault(2, 3, DEFAULT)).isEqualTo("valueC"); 91 assertThat(graph.edgeValueOrDefault(4, 4, DEFAULT)).isEqualTo("valueD"); 92 93 String toString = graph.toString(); 94 assertThat(toString).contains("valueA"); 95 assertThat(toString).contains("valueB"); 96 assertThat(toString).contains("valueC"); 97 assertThat(toString).contains("valueD"); 98 } 99 100 @Test undirectedGraph()101 public void undirectedGraph() { 102 graph = ValueGraphBuilder.undirected().allowsSelfLoops(true).build(); 103 graph.putEdgeValue(1, 2, "valueA"); 104 graph.putEdgeValue(2, 1, "valueB"); // overwrites valueA in undirected case 105 graph.putEdgeValue(2, 3, "valueC"); 106 graph.putEdgeValue(4, 4, "valueD"); 107 108 assertThat(graph.edgeValueOrDefault(1, 2, null)).isEqualTo("valueB"); 109 assertThat(graph.edgeValueOrDefault(2, 1, null)).isEqualTo("valueB"); 110 assertThat(graph.edgeValueOrDefault(2, 3, null)).isEqualTo("valueC"); 111 assertThat(graph.edgeValueOrDefault(4, 4, null)).isEqualTo("valueD"); 112 assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo("valueB"); 113 assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo("valueB"); 114 assertThat(graph.edgeValueOrDefault(2, 3, DEFAULT)).isEqualTo("valueC"); 115 assertThat(graph.edgeValueOrDefault(4, 4, DEFAULT)).isEqualTo("valueD"); 116 117 String toString = graph.toString(); 118 assertThat(toString).doesNotContain("valueA"); 119 assertThat(toString).contains("valueB"); 120 assertThat(toString).contains("valueC"); 121 assertThat(toString).contains("valueD"); 122 } 123 124 @Test incidentEdgeOrder_unordered()125 public void incidentEdgeOrder_unordered() { 126 graph = ValueGraphBuilder.directed().incidentEdgeOrder(ElementOrder.unordered()).build(); 127 assertThat(graph.incidentEdgeOrder()).isEqualTo(ElementOrder.unordered()); 128 } 129 130 @Test incidentEdgeOrder_stable()131 public void incidentEdgeOrder_stable() { 132 graph = ValueGraphBuilder.directed().incidentEdgeOrder(ElementOrder.stable()).build(); 133 assertThat(graph.incidentEdgeOrder()).isEqualTo(ElementOrder.stable()); 134 } 135 136 @Test hasEdgeConnecting_directed_correct()137 public void hasEdgeConnecting_directed_correct() { 138 graph = ValueGraphBuilder.directed().build(); 139 graph.putEdgeValue(1, 2, "A"); 140 assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(1, 2))).isTrue(); 141 } 142 143 @Test hasEdgeConnecting_directed_backwards()144 public void hasEdgeConnecting_directed_backwards() { 145 graph = ValueGraphBuilder.directed().build(); 146 graph.putEdgeValue(1, 2, "A"); 147 assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(2, 1))).isFalse(); 148 } 149 150 @Test hasEdgeConnecting_directed_mismatch()151 public void hasEdgeConnecting_directed_mismatch() { 152 graph = ValueGraphBuilder.directed().build(); 153 graph.putEdgeValue(1, 2, "A"); 154 assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(1, 2))).isFalse(); 155 assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(2, 1))).isFalse(); 156 } 157 158 @Test hasEdgeConnecting_undirected_correct()159 public void hasEdgeConnecting_undirected_correct() { 160 graph = ValueGraphBuilder.undirected().build(); 161 graph.putEdgeValue(1, 2, "A"); 162 assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(1, 2))).isTrue(); 163 } 164 165 @Test hasEdgeConnecting_undirected_backwards()166 public void hasEdgeConnecting_undirected_backwards() { 167 graph = ValueGraphBuilder.undirected().build(); 168 graph.putEdgeValue(1, 2, "A"); 169 assertThat(graph.hasEdgeConnecting(EndpointPair.unordered(2, 1))).isTrue(); 170 } 171 172 @Test hasEdgeConnecting_undirected_mismatch()173 public void hasEdgeConnecting_undirected_mismatch() { 174 graph = ValueGraphBuilder.undirected().build(); 175 graph.putEdgeValue(1, 2, "A"); 176 assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(1, 2))).isTrue(); 177 assertThat(graph.hasEdgeConnecting(EndpointPair.ordered(2, 1))).isTrue(); 178 } 179 180 @Test edgeValueOrDefault_directed_correct()181 public void edgeValueOrDefault_directed_correct() { 182 graph = ValueGraphBuilder.directed().build(); 183 graph.putEdgeValue(1, 2, "A"); 184 assertThat(graph.edgeValueOrDefault(EndpointPair.ordered(1, 2), "default")).isEqualTo("A"); 185 } 186 187 @Test edgeValueOrDefault_directed_backwards()188 public void edgeValueOrDefault_directed_backwards() { 189 graph = ValueGraphBuilder.directed().build(); 190 graph.putEdgeValue(1, 2, "A"); 191 assertThat(graph.edgeValueOrDefault(EndpointPair.ordered(2, 1), "default")) 192 .isEqualTo("default"); 193 } 194 195 @Test edgeValueOrDefault_directed_mismatch()196 public void edgeValueOrDefault_directed_mismatch() { 197 graph = ValueGraphBuilder.directed().build(); 198 graph.putEdgeValue(1, 2, "A"); 199 try { 200 String unused = graph.edgeValueOrDefault(EndpointPair.unordered(1, 2), "default"); 201 unused = graph.edgeValueOrDefault(EndpointPair.unordered(2, 1), "default"); 202 fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH); 203 } catch (IllegalArgumentException e) { 204 assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH); 205 } 206 } 207 208 @Test edgeValueOrDefault_undirected_correct()209 public void edgeValueOrDefault_undirected_correct() { 210 graph = ValueGraphBuilder.undirected().build(); 211 graph.putEdgeValue(1, 2, "A"); 212 assertThat(graph.edgeValueOrDefault(EndpointPair.unordered(1, 2), "default")).isEqualTo("A"); 213 } 214 215 @Test edgeValueOrDefault_undirected_backwards()216 public void edgeValueOrDefault_undirected_backwards() { 217 graph = ValueGraphBuilder.undirected().build(); 218 graph.putEdgeValue(1, 2, "A"); 219 assertThat(graph.edgeValueOrDefault(EndpointPair.unordered(2, 1), "default")).isEqualTo("A"); 220 } 221 222 @Test edgeValueOrDefault_undirected_mismatch()223 public void edgeValueOrDefault_undirected_mismatch() { 224 graph = ValueGraphBuilder.undirected().build(); 225 graph.putEdgeValue(1, 2, "A"); 226 assertThat(graph.edgeValueOrDefault(EndpointPair.ordered(2, 1), "default")).isEqualTo("A"); 227 assertThat(graph.edgeValueOrDefault(EndpointPair.ordered(2, 1), "default")).isEqualTo("A"); 228 } 229 230 @Test putEdgeValue_directed()231 public void putEdgeValue_directed() { 232 graph = ValueGraphBuilder.directed().build(); 233 234 assertThat(graph.putEdgeValue(1, 2, "valueA")).isNull(); 235 assertThat(graph.putEdgeValue(2, 1, "valueB")).isNull(); 236 assertThat(graph.putEdgeValue(1, 2, "valueC")).isEqualTo("valueA"); 237 assertThat(graph.putEdgeValue(2, 1, "valueD")).isEqualTo("valueB"); 238 } 239 240 @Test putEdgeValue_directed_orderMismatch()241 public void putEdgeValue_directed_orderMismatch() { 242 graph = ValueGraphBuilder.directed().build(); 243 try { 244 graph.putEdgeValue(EndpointPair.unordered(1, 2), "irrelevant"); 245 fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH); 246 } catch (IllegalArgumentException e) { 247 assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH); 248 } 249 } 250 251 @Test putEdgeValue_undirected_orderMismatch()252 public void putEdgeValue_undirected_orderMismatch() { 253 graph = ValueGraphBuilder.undirected().build(); 254 assertThat(graph.putEdgeValue(EndpointPair.ordered(1, 2), "irrelevant")).isNull(); 255 } 256 257 @Test putEdgeValue_undirected()258 public void putEdgeValue_undirected() { 259 graph = ValueGraphBuilder.undirected().build(); 260 261 assertThat(graph.putEdgeValue(1, 2, "valueA")).isNull(); 262 assertThat(graph.putEdgeValue(2, 1, "valueB")).isEqualTo("valueA"); 263 assertThat(graph.putEdgeValue(1, 2, "valueC")).isEqualTo("valueB"); 264 assertThat(graph.putEdgeValue(2, 1, "valueD")).isEqualTo("valueC"); 265 } 266 267 @Test removeEdge_directed()268 public void removeEdge_directed() { 269 graph = ValueGraphBuilder.directed().build(); 270 graph.putEdgeValue(1, 2, "valueA"); 271 graph.putEdgeValue(2, 1, "valueB"); 272 graph.putEdgeValue(2, 3, "valueC"); 273 274 assertThat(graph.removeEdge(1, 2)).isEqualTo("valueA"); 275 assertThat(graph.removeEdge(1, 2)).isNull(); 276 assertThat(graph.removeEdge(2, 1)).isEqualTo("valueB"); 277 assertThat(graph.removeEdge(2, 1)).isNull(); 278 assertThat(graph.removeEdge(2, 3)).isEqualTo("valueC"); 279 assertThat(graph.removeEdge(2, 3)).isNull(); 280 } 281 282 @Test removeEdge_undirected()283 public void removeEdge_undirected() { 284 graph = ValueGraphBuilder.undirected().build(); 285 graph.putEdgeValue(1, 2, "valueA"); 286 graph.putEdgeValue(2, 1, "valueB"); 287 graph.putEdgeValue(2, 3, "valueC"); 288 289 assertThat(graph.removeEdge(1, 2)).isEqualTo("valueB"); 290 assertThat(graph.removeEdge(1, 2)).isNull(); 291 assertThat(graph.removeEdge(2, 1)).isNull(); 292 assertThat(graph.removeEdge(2, 3)).isEqualTo("valueC"); 293 assertThat(graph.removeEdge(2, 3)).isNull(); 294 } 295 296 @Test removeEdge_directed_orderMismatch()297 public void removeEdge_directed_orderMismatch() { 298 graph = ValueGraphBuilder.directed().build(); 299 graph.putEdgeValue(1, 2, "1->2"); 300 graph.putEdgeValue(2, 1, "2->1"); 301 try { 302 graph.removeEdge(EndpointPair.unordered(1, 2)); 303 graph.removeEdge(EndpointPair.unordered(2, 1)); 304 fail("Expected IllegalArgumentException: " + ENDPOINTS_MISMATCH); 305 } catch (IllegalArgumentException e) { 306 assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH); 307 } 308 } 309 310 @Test removeEdge_undirected_orderMismatch()311 public void removeEdge_undirected_orderMismatch() { 312 graph = ValueGraphBuilder.undirected().build(); 313 graph.putEdgeValue(1, 2, "1-2"); 314 assertThat(graph.removeEdge(EndpointPair.ordered(1, 2))).isEqualTo("1-2"); 315 } 316 317 @Test edgeValue_missing()318 public void edgeValue_missing() { 319 graph = ValueGraphBuilder.directed().build(); 320 321 assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo(DEFAULT); 322 assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo(DEFAULT); 323 assertThat(graph.edgeValueOrDefault(1, 2, null)).isNull(); 324 assertThat(graph.edgeValueOrDefault(2, 1, null)).isNull(); 325 326 graph.putEdgeValue(1, 2, "valueA"); 327 graph.putEdgeValue(2, 1, "valueB"); 328 assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo("valueA"); 329 assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo("valueB"); 330 assertThat(graph.edgeValueOrDefault(1, 2, null)).isEqualTo("valueA"); 331 assertThat(graph.edgeValueOrDefault(2, 1, null)).isEqualTo("valueB"); 332 333 graph.removeEdge(1, 2); 334 graph.putEdgeValue(2, 1, "valueC"); 335 assertThat(graph.edgeValueOrDefault(1, 2, DEFAULT)).isEqualTo(DEFAULT); 336 assertThat(graph.edgeValueOrDefault(2, 1, DEFAULT)).isEqualTo("valueC"); 337 assertThat(graph.edgeValueOrDefault(1, 2, null)).isNull(); 338 assertThat(graph.edgeValueOrDefault(2, 1, null)).isEqualTo("valueC"); 339 } 340 341 @Test equivalence_considersEdgeValue()342 public void equivalence_considersEdgeValue() { 343 graph = ValueGraphBuilder.undirected().build(); 344 graph.putEdgeValue(1, 2, "valueA"); 345 346 MutableValueGraph<Integer, String> otherGraph = ValueGraphBuilder.undirected().build(); 347 otherGraph.putEdgeValue(1, 2, "valueA"); 348 assertThat(graph).isEqualTo(otherGraph); 349 350 otherGraph.putEdgeValue(1, 2, "valueB"); 351 assertThat(graph).isNotEqualTo(otherGraph); // values differ 352 } 353 354 @Test incidentEdges_stableIncidentEdgeOrder_preservesIncidentEdgesOrder_directed()355 public void incidentEdges_stableIncidentEdgeOrder_preservesIncidentEdgesOrder_directed() { 356 graph = ValueGraphBuilder.directed().incidentEdgeOrder(ElementOrder.stable()).build(); 357 graph.putEdgeValue(2, 1, "2-1"); 358 graph.putEdgeValue(2, 3, "2-3"); 359 graph.putEdgeValue(1, 2, "1-2"); 360 361 assertThat(graph.incidentEdges(2)) 362 .containsExactly( 363 EndpointPair.ordered(2, 1), EndpointPair.ordered(2, 3), EndpointPair.ordered(1, 2)) 364 .inOrder(); 365 } 366 367 @Test incidentEdges_stableIncidentEdgeOrder_preservesIncidentEdgesOrder_undirected()368 public void incidentEdges_stableIncidentEdgeOrder_preservesIncidentEdgesOrder_undirected() { 369 graph = ValueGraphBuilder.undirected().incidentEdgeOrder(ElementOrder.stable()).build(); 370 graph.putEdgeValue(2, 3, "2-3"); 371 graph.putEdgeValue(2, 1, "2-1"); 372 graph.putEdgeValue(2, 4, "2-4"); 373 graph.putEdgeValue(1, 2, "1-2"); // Duplicate nodes, different value 374 375 assertThat(graph.incidentEdges(2)) 376 .containsExactly( 377 EndpointPair.unordered(2, 3), 378 EndpointPair.unordered(1, 2), 379 EndpointPair.unordered(2, 4)) 380 .inOrder(); 381 } 382 383 @Test concurrentIteration()384 public void concurrentIteration() throws Exception { 385 graph = ValueGraphBuilder.directed().build(); 386 graph.putEdgeValue(1, 2, "A"); 387 graph.putEdgeValue(3, 4, "B"); 388 graph.putEdgeValue(5, 6, "C"); 389 390 int threadCount = 20; 391 ExecutorService executor = newFixedThreadPool(threadCount); 392 final CyclicBarrier barrier = new CyclicBarrier(threadCount); 393 ImmutableList.Builder<Future<?>> futures = ImmutableList.builder(); 394 for (int i = 0; i < threadCount; i++) { 395 futures.add( 396 executor.submit( 397 new Callable<Object>() { 398 @Override 399 public Object call() throws Exception { 400 barrier.await(); 401 Integer first = graph.nodes().iterator().next(); 402 for (Integer node : graph.nodes()) { 403 Set<Integer> unused = graph.successors(node); 404 } 405 /* 406 * Also look up an earlier node so that, if the graph is using MapRetrievalCache, 407 * we read one of the fields declared in that class. 408 */ 409 Set<Integer> unused = graph.successors(first); 410 return null; 411 } 412 })); 413 } 414 415 // For more about this test, see the equivalent in AbstractNetworkTest. 416 for (Future<?> future : futures.build()) { 417 future.get(); 418 } 419 executor.shutdown(); 420 } 421 } 422