• 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.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