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