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