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