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