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