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