• 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.graph.TestUtil.assertEdgeNotInGraphErrorMessage;
21 import static com.google.common.truth.Truth.assertThat;
22 import static com.google.common.truth.TruthJUnit.assume;
23 import static org.junit.Assert.assertThrows;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26 
27 import com.google.common.collect.ImmutableSet;
28 import java.util.Collections;
29 import java.util.Optional;
30 import java.util.Set;
31 import org.junit.After;
32 import org.junit.Test;
33 
34 /**
35  * Abstract base class for testing directed {@link Network} implementations defined in this package.
36  */
37 public abstract class AbstractStandardDirectedNetworkTest extends AbstractNetworkTest {
38 
39   @After
validateSourceAndTarget()40   public void validateSourceAndTarget() {
41     for (Integer node : network.nodes()) {
42       for (String inEdge : network.inEdges(node)) {
43         EndpointPair<Integer> endpointPair = network.incidentNodes(inEdge);
44         assertThat(endpointPair.source()).isEqualTo(endpointPair.adjacentNode(node));
45         assertThat(endpointPair.target()).isEqualTo(node);
46       }
47 
48       for (String outEdge : network.outEdges(node)) {
49         EndpointPair<Integer> endpointPair = network.incidentNodes(outEdge);
50         assertThat(endpointPair.source()).isEqualTo(node);
51         assertThat(endpointPair.target()).isEqualTo(endpointPair.adjacentNode(node));
52       }
53 
54       for (Integer adjacentNode : network.adjacentNodes(node)) {
55         Set<String> edges = network.edgesConnecting(node, adjacentNode);
56         Set<String> antiParallelEdges = network.edgesConnecting(adjacentNode, node);
57         assertThat(node.equals(adjacentNode) || Collections.disjoint(edges, antiParallelEdges))
58             .isTrue();
59       }
60     }
61   }
62 
63   @Override
64   @Test
nodes_checkReturnedSetMutability()65   public void nodes_checkReturnedSetMutability() {
66     assume().that(graphIsMutable()).isTrue();
67 
68     Set<Integer> nodes = network.nodes();
69     UnsupportedOperationException e =
70         assertThrows(UnsupportedOperationException.class, () -> nodes.add(N2));
71     addNode(N1);
72     assertThat(network.nodes()).containsExactlyElementsIn(nodes);
73   }
74 
75   @Override
76   @Test
edges_checkReturnedSetMutability()77   public void edges_checkReturnedSetMutability() {
78     assume().that(graphIsMutable()).isTrue();
79 
80     Set<String> edges = network.edges();
81     UnsupportedOperationException e =
82         assertThrows(UnsupportedOperationException.class, () -> edges.add(E12));
83     addEdge(N1, N2, E12);
84     assertThat(network.edges()).containsExactlyElementsIn(edges);
85   }
86 
87   @Override
88   @Test
incidentEdges_checkReturnedSetMutability()89   public void incidentEdges_checkReturnedSetMutability() {
90     assume().that(graphIsMutable()).isTrue();
91 
92     addNode(N1);
93     Set<String> incidentEdges = network.incidentEdges(N1);
94     UnsupportedOperationException e =
95         assertThrows(UnsupportedOperationException.class, () -> incidentEdges.add(E12));
96     addEdge(N1, N2, E12);
97     assertThat(network.incidentEdges(N1)).containsExactlyElementsIn(incidentEdges);
98   }
99 
100   @Override
101   @Test
adjacentNodes_checkReturnedSetMutability()102   public void adjacentNodes_checkReturnedSetMutability() {
103     assume().that(graphIsMutable()).isTrue();
104 
105     addNode(N1);
106     Set<Integer> adjacentNodes = network.adjacentNodes(N1);
107     UnsupportedOperationException e =
108         assertThrows(UnsupportedOperationException.class, () -> adjacentNodes.add(N2));
109     addEdge(N1, N2, E12);
110     assertThat(network.adjacentNodes(N1)).containsExactlyElementsIn(adjacentNodes);
111   }
112 
113   @Override
adjacentEdges_checkReturnedSetMutability()114   public void adjacentEdges_checkReturnedSetMutability() {
115     assume().that(graphIsMutable()).isTrue();
116 
117     addEdge(N1, N2, E12);
118     Set<String> adjacentEdges = network.adjacentEdges(E12);
119     try {
120       adjacentEdges.add(E23);
121       fail(ERROR_MODIFIABLE_COLLECTION);
122     } catch (UnsupportedOperationException e) {
123       addEdge(N2, N3, E23);
124       assertThat(network.adjacentEdges(E12)).containsExactlyElementsIn(adjacentEdges);
125     }
126   }
127 
128   @Override
129   @Test
edgesConnecting_checkReturnedSetMutability()130   public void edgesConnecting_checkReturnedSetMutability() {
131     assume().that(graphIsMutable()).isTrue();
132 
133     addNode(N1);
134     addNode(N2);
135     Set<String> edgesConnecting = network.edgesConnecting(N1, N2);
136     UnsupportedOperationException e =
137         assertThrows(UnsupportedOperationException.class, () -> edgesConnecting.add(E23));
138     addEdge(N1, N2, E12);
139     assertThat(network.edgesConnecting(N1, N2)).containsExactlyElementsIn(edgesConnecting);
140   }
141 
142   @Override
143   @Test
inEdges_checkReturnedSetMutability()144   public void inEdges_checkReturnedSetMutability() {
145     assume().that(graphIsMutable()).isTrue();
146 
147     addNode(N2);
148     Set<String> inEdges = network.inEdges(N2);
149     UnsupportedOperationException e =
150         assertThrows(UnsupportedOperationException.class, () -> inEdges.add(E12));
151     addEdge(N1, N2, E12);
152     assertThat(network.inEdges(N2)).containsExactlyElementsIn(inEdges);
153   }
154 
155   @Override
156   @Test
outEdges_checkReturnedSetMutability()157   public void outEdges_checkReturnedSetMutability() {
158     assume().that(graphIsMutable()).isTrue();
159 
160     addNode(N1);
161     Set<String> outEdges = network.outEdges(N1);
162     UnsupportedOperationException e =
163         assertThrows(UnsupportedOperationException.class, () -> outEdges.add(E12));
164     addEdge(N1, N2, E12);
165     assertThat(network.outEdges(N1)).containsExactlyElementsIn(outEdges);
166   }
167 
168   @Override
169   @Test
predecessors_checkReturnedSetMutability()170   public void predecessors_checkReturnedSetMutability() {
171     assume().that(graphIsMutable()).isTrue();
172 
173     addNode(N2);
174     Set<Integer> predecessors = network.predecessors(N2);
175     UnsupportedOperationException e =
176         assertThrows(UnsupportedOperationException.class, () -> predecessors.add(N1));
177     addEdge(N1, N2, E12);
178     assertThat(network.predecessors(N2)).containsExactlyElementsIn(predecessors);
179   }
180 
181   @Override
182   @Test
successors_checkReturnedSetMutability()183   public void successors_checkReturnedSetMutability() {
184     assume().that(graphIsMutable()).isTrue();
185 
186     addNode(N1);
187     Set<Integer> successors = network.successors(N1);
188     UnsupportedOperationException e =
189         assertThrows(UnsupportedOperationException.class, () -> successors.add(N2));
190     addEdge(N1, N2, E12);
191     assertThat(successors).containsExactlyElementsIn(network.successors(N1));
192   }
193 
194   @Test
edges_containsOrderMismatch()195   public void edges_containsOrderMismatch() {
196     addEdge(N1, N2, E12);
197     EndpointPair<Integer> endpointsN1N2 = EndpointPair.unordered(N1, N2);
198     EndpointPair<Integer> endpointsN2N1 = EndpointPair.unordered(N2, N1);
199     assertThat(network.asGraph().edges()).doesNotContain(endpointsN1N2);
200     assertThat(network.asGraph().edges()).doesNotContain(endpointsN2N1);
201   }
202 
203   @Test
edgesConnecting_orderMismatch()204   public void edgesConnecting_orderMismatch() {
205     addEdge(N1, N2, E12);
206     IllegalArgumentException e =
207         assertThrows(
208             IllegalArgumentException.class,
209             () -> {
210               Set<String> unused = network.edgesConnecting(EndpointPair.unordered(N1, N2));
211             });
212     assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH);
213   }
214 
215   @Test
edgeConnecting_orderMismatch()216   public void edgeConnecting_orderMismatch() {
217     addEdge(N1, N2, E12);
218     IllegalArgumentException e =
219         assertThrows(
220             IllegalArgumentException.class,
221             () -> {
222               Optional<String> unused = network.edgeConnecting(EndpointPair.unordered(N1, N2));
223             });
224     assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH);
225   }
226 
227   @Test
edgeConnectingOrNull_orderMismatch()228   public void edgeConnectingOrNull_orderMismatch() {
229     addEdge(N1, N2, E12);
230     IllegalArgumentException e =
231         assertThrows(
232             IllegalArgumentException.class,
233             () -> {
234               String unused = network.edgeConnectingOrNull(EndpointPair.unordered(N1, N2));
235             });
236     assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH);
237   }
238 
239   @Override
240   @Test
incidentNodes_oneEdge()241   public void incidentNodes_oneEdge() {
242     addEdge(N1, N2, E12);
243     assertThat(network.incidentNodes(E12).source()).isEqualTo(N1);
244     assertThat(network.incidentNodes(E12).target()).isEqualTo(N2);
245   }
246 
247   @Test
edgesConnecting_oneEdge()248   public void edgesConnecting_oneEdge() {
249     addEdge(N1, N2, E12);
250     assertThat(network.edgesConnecting(N1, N2)).containsExactly(E12);
251     // Passed nodes should be in the correct edge direction, first is the
252     // source node and the second is the target node
253     assertThat(network.edgesConnecting(N2, N1)).isEmpty();
254   }
255 
256   @Test
inEdges_oneEdge()257   public void inEdges_oneEdge() {
258     addEdge(N1, N2, E12);
259     assertThat(network.inEdges(N2)).containsExactly(E12);
260     // Edge direction handled correctly
261     assertThat(network.inEdges(N1)).isEmpty();
262   }
263 
264   @Test
outEdges_oneEdge()265   public void outEdges_oneEdge() {
266     addEdge(N1, N2, E12);
267     assertThat(network.outEdges(N1)).containsExactly(E12);
268     // Edge direction handled correctly
269     assertThat(network.outEdges(N2)).isEmpty();
270   }
271 
272   @Test
predecessors_oneEdge()273   public void predecessors_oneEdge() {
274     addEdge(N1, N2, E12);
275     assertThat(network.predecessors(N2)).containsExactly(N1);
276     // Edge direction handled correctly
277     assertThat(network.predecessors(N1)).isEmpty();
278   }
279 
280   @Test
successors_oneEdge()281   public void successors_oneEdge() {
282     addEdge(N1, N2, E12);
283     assertThat(network.successors(N1)).containsExactly(N2);
284     // Edge direction handled correctly
285     assertThat(network.successors(N2)).isEmpty();
286   }
287 
288   @Test
source_oneEdge()289   public void source_oneEdge() {
290     addEdge(N1, N2, E12);
291     assertThat(network.incidentNodes(E12).source()).isEqualTo(N1);
292   }
293 
294   @Test
source_edgeNotInGraph()295   public void source_edgeNotInGraph() {
296     IllegalArgumentException e =
297         assertThrows(
298             IllegalArgumentException.class,
299             () -> network.incidentNodes(EDGE_NOT_IN_GRAPH).source());
300     assertEdgeNotInGraphErrorMessage(e);
301   }
302 
303   @Test
target_oneEdge()304   public void target_oneEdge() {
305     addEdge(N1, N2, E12);
306     assertThat(network.incidentNodes(E12).target()).isEqualTo(N2);
307   }
308 
309   @Test
target_edgeNotInGraph()310   public void target_edgeNotInGraph() {
311     IllegalArgumentException e =
312         assertThrows(
313             IllegalArgumentException.class,
314             () -> network.incidentNodes(EDGE_NOT_IN_GRAPH).target());
315     assertEdgeNotInGraphErrorMessage(e);
316   }
317 
318   @Test
inDegree_oneEdge()319   public void inDegree_oneEdge() {
320     addEdge(N1, N2, E12);
321     assertThat(network.inDegree(N2)).isEqualTo(1);
322     // Edge direction handled correctly
323     assertThat(network.inDegree(N1)).isEqualTo(0);
324   }
325 
326   @Test
outDegree_oneEdge()327   public void outDegree_oneEdge() {
328     addEdge(N1, N2, E12);
329     assertThat(network.outDegree(N1)).isEqualTo(1);
330     // Edge direction handled correctly
331     assertThat(network.outDegree(N2)).isEqualTo(0);
332   }
333 
334   @Test
edges_selfLoop()335   public void edges_selfLoop() {
336     assume().that(network.allowsSelfLoops()).isTrue();
337 
338     addEdge(N1, N1, E11);
339     assertThat(network.edges()).containsExactly(E11);
340   }
341 
342   @Test
incidentEdges_selfLoop()343   public void incidentEdges_selfLoop() {
344     assume().that(network.allowsSelfLoops()).isTrue();
345 
346     addEdge(N1, N1, E11);
347     assertThat(network.incidentEdges(N1)).containsExactly(E11);
348   }
349 
350   @Test
incidentNodes_selfLoop()351   public void incidentNodes_selfLoop() {
352     assume().that(network.allowsSelfLoops()).isTrue();
353 
354     addEdge(N1, N1, E11);
355     assertThat(network.incidentNodes(E11).source()).isEqualTo(N1);
356     assertThat(network.incidentNodes(E11).target()).isEqualTo(N1);
357   }
358 
359   @Test
adjacentNodes_selfLoop()360   public void adjacentNodes_selfLoop() {
361     assume().that(network.allowsSelfLoops()).isTrue();
362 
363     addEdge(N1, N1, E11);
364     addEdge(N1, N2, E12);
365     assertThat(network.adjacentNodes(N1)).containsExactly(N1, N2);
366   }
367 
368   @Test
adjacentEdges_selfLoop()369   public void adjacentEdges_selfLoop() {
370     assume().that(network.allowsSelfLoops()).isTrue();
371 
372     addEdge(N1, N1, E11);
373     addEdge(N1, N2, E12);
374     assertThat(network.adjacentEdges(E11)).containsExactly(E12);
375   }
376 
377   @Test
edgesConnecting_selfLoop()378   public void edgesConnecting_selfLoop() {
379     assume().that(network.allowsSelfLoops()).isTrue();
380 
381     addEdge(N1, N1, E11);
382     assertThat(network.edgesConnecting(N1, N1)).containsExactly(E11);
383     addEdge(N1, N2, E12);
384     assertThat(network.edgesConnecting(N1, N2)).containsExactly(E12);
385     assertThat(network.edgesConnecting(N1, N1)).containsExactly(E11);
386   }
387 
388   @Test
inEdges_selfLoop()389   public void inEdges_selfLoop() {
390     assume().that(network.allowsSelfLoops()).isTrue();
391 
392     addEdge(N1, N1, E11);
393     assertThat(network.inEdges(N1)).containsExactly(E11);
394     addEdge(N4, N1, E41);
395     assertThat(network.inEdges(N1)).containsExactly(E11, E41);
396   }
397 
398   @Test
outEdges_selfLoop()399   public void outEdges_selfLoop() {
400     assume().that(network.allowsSelfLoops()).isTrue();
401 
402     addEdge(N1, N1, E11);
403     assertThat(network.outEdges(N1)).containsExactly(E11);
404     addEdge(N1, N2, E12);
405     assertThat(network.outEdges(N1)).containsExactly(E11, E12);
406   }
407 
408   @Test
predecessors_selfLoop()409   public void predecessors_selfLoop() {
410     assume().that(network.allowsSelfLoops()).isTrue();
411 
412     addEdge(N1, N1, E11);
413     assertThat(network.predecessors(N1)).containsExactly(N1);
414     addEdge(N4, N1, E41);
415     assertThat(network.predecessors(N1)).containsExactly(N1, N4);
416   }
417 
418   @Test
successors_selfLoop()419   public void successors_selfLoop() {
420     assume().that(network.allowsSelfLoops()).isTrue();
421 
422     addEdge(N1, N1, E11);
423     assertThat(network.successors(N1)).containsExactly(N1);
424     addEdge(N1, N2, E12);
425     assertThat(network.successors(N1)).containsExactly(N1, N2);
426   }
427 
428   @Test
source_selfLoop()429   public void source_selfLoop() {
430     assume().that(network.allowsSelfLoops()).isTrue();
431 
432     addEdge(N1, N1, E11);
433     assertThat(network.incidentNodes(E11).source()).isEqualTo(N1);
434   }
435 
436   @Test
target_selfLoop()437   public void target_selfLoop() {
438     assume().that(network.allowsSelfLoops()).isTrue();
439 
440     addEdge(N1, N1, E11);
441     assertThat(network.incidentNodes(E11).target()).isEqualTo(N1);
442   }
443 
444   @Test
degree_selfLoop()445   public void degree_selfLoop() {
446     assume().that(network.allowsSelfLoops()).isTrue();
447 
448     addEdge(N1, N1, E11);
449     assertThat(network.degree(N1)).isEqualTo(2);
450     addEdge(N1, N2, E12);
451     assertThat(network.degree(N1)).isEqualTo(3);
452   }
453 
454   @Test
inDegree_selfLoop()455   public void inDegree_selfLoop() {
456     assume().that(network.allowsSelfLoops()).isTrue();
457 
458     addEdge(N1, N1, E11);
459     assertThat(network.inDegree(N1)).isEqualTo(1);
460     addEdge(N4, N1, E41);
461     assertThat(network.inDegree(N1)).isEqualTo(2);
462   }
463 
464   @Test
outDegree_selfLoop()465   public void outDegree_selfLoop() {
466     assume().that(network.allowsSelfLoops()).isTrue();
467 
468     addEdge(N1, N1, E11);
469     assertThat(network.outDegree(N1)).isEqualTo(1);
470     addEdge(N1, N2, E12);
471     assertThat(network.outDegree(N1)).isEqualTo(2);
472   }
473 
474   // Element Mutation
475 
476   @Test
addEdge_existingNodes()477   public void addEdge_existingNodes() {
478     assume().that(graphIsMutable()).isTrue();
479 
480     // Adding nodes initially for safety (insulating from possible future
481     // modifications to proxy methods)
482     addNode(N1);
483     addNode(N2);
484     assertThat(networkAsMutableNetwork.addEdge(N1, N2, E12)).isTrue();
485     assertThat(network.edges()).contains(E12);
486     assertThat(network.edgesConnecting(N1, N2)).containsExactly(E12);
487     // Direction of the added edge is correctly handled
488     assertThat(network.edgesConnecting(N2, N1)).isEmpty();
489   }
490 
491   @Test
addEdge_existingEdgeBetweenSameNodes()492   public void addEdge_existingEdgeBetweenSameNodes() {
493     assume().that(graphIsMutable()).isTrue();
494 
495     addEdge(N1, N2, E12);
496     ImmutableSet<String> edges = ImmutableSet.copyOf(network.edges());
497     assertThat(networkAsMutableNetwork.addEdge(N1, N2, E12)).isFalse();
498     assertThat(network.edges()).containsExactlyElementsIn(edges);
499   }
500 
501   @Test
addEdge_existingEdgeBetweenDifferentNodes()502   public void addEdge_existingEdgeBetweenDifferentNodes() {
503     assume().that(graphIsMutable()).isTrue();
504 
505     addEdge(N1, N2, E12);
506     IllegalArgumentException e =
507         assertThrows(
508             IllegalArgumentException.class, () -> networkAsMutableNetwork.addEdge(N4, N5, E12));
509     assertThat(e).hasMessageThat().contains(ERROR_REUSE_EDGE);
510     e = assertThrows(IllegalArgumentException.class, () -> addEdge(N2, N1, E12));
511     assertThat(e).hasMessageThat().contains(ERROR_REUSE_EDGE);
512   }
513 
514   @Test
addEdge_parallelEdge_notAllowed()515   public void addEdge_parallelEdge_notAllowed() {
516     assume().that(graphIsMutable()).isTrue();
517     assume().that(network.allowsParallelEdges()).isFalse();
518 
519     addEdge(N1, N2, E12);
520     IllegalArgumentException e =
521         assertThrows(
522             IllegalArgumentException.class,
523             () -> networkAsMutableNetwork.addEdge(N1, N2, EDGE_NOT_IN_GRAPH));
524     assertThat(e).hasMessageThat().contains(ERROR_PARALLEL_EDGE);
525   }
526 
527   @Test
addEdge_parallelEdge_allowsParallelEdges()528   public void addEdge_parallelEdge_allowsParallelEdges() {
529     assume().that(graphIsMutable()).isTrue();
530     assume().that(network.allowsParallelEdges()).isTrue();
531 
532     assertTrue(networkAsMutableNetwork.addEdge(N1, N2, E12));
533     assertTrue(networkAsMutableNetwork.addEdge(N1, N2, E12_A));
534     assertThat(network.edgesConnecting(N1, N2)).containsExactly(E12, E12_A);
535   }
536 
537   @Test
addEdge_orderMismatch()538   public void addEdge_orderMismatch() {
539     assume().that(graphIsMutable()).isTrue();
540 
541     EndpointPair<Integer> endpoints = EndpointPair.unordered(N1, N2);
542     IllegalArgumentException e =
543         assertThrows(
544             IllegalArgumentException.class, () -> networkAsMutableNetwork.addEdge(endpoints, E12));
545     assertThat(e).hasMessageThat().contains(ENDPOINTS_MISMATCH);
546   }
547 
548   @Test
addEdge_selfLoop_notAllowed()549   public void addEdge_selfLoop_notAllowed() {
550     assume().that(graphIsMutable()).isTrue();
551     assume().that(network.allowsSelfLoops()).isFalse();
552 
553     IllegalArgumentException e =
554         assertThrows(
555             IllegalArgumentException.class, () -> networkAsMutableNetwork.addEdge(N1, N1, E11));
556     assertThat(e).hasMessageThat().contains(ERROR_SELF_LOOP);
557   }
558 
559   /**
560    * This test checks an implementation dependent feature. It tests that the method {@code addEdge}
561    * will silently add the missing nodes to the graph, then add the edge connecting them. We are not
562    * using the proxy methods here as we want to test {@code addEdge} when the end-points are not
563    * elements of the graph.
564    */
565   @Test
addEdge_nodesNotInGraph()566   public void addEdge_nodesNotInGraph() {
567     assume().that(graphIsMutable()).isTrue();
568 
569     networkAsMutableNetwork.addNode(N1);
570     assertTrue(networkAsMutableNetwork.addEdge(N1, N5, E15));
571     assertTrue(networkAsMutableNetwork.addEdge(N4, N1, E41));
572     assertTrue(networkAsMutableNetwork.addEdge(N2, N3, E23));
573     assertThat(network.nodes()).containsExactly(N1, N5, N4, N2, N3);
574     assertThat(network.edges()).containsExactly(E15, E41, E23);
575     assertThat(network.edgesConnecting(N1, N5)).containsExactly(E15);
576     assertThat(network.edgesConnecting(N4, N1)).containsExactly(E41);
577     assertThat(network.edgesConnecting(N2, N3)).containsExactly(E23);
578     // Direction of the added edge is correctly handled
579     assertThat(network.edgesConnecting(N3, N2)).isEmpty();
580   }
581 
582   @Test
addEdge_selfLoop_allowed()583   public void addEdge_selfLoop_allowed() {
584     assume().that(graphIsMutable()).isTrue();
585     assume().that(network.allowsSelfLoops()).isTrue();
586 
587     assertThat(networkAsMutableNetwork.addEdge(N1, N1, E11)).isTrue();
588     assertThat(network.edges()).contains(E11);
589     assertThat(network.edgesConnecting(N1, N1)).containsExactly(E11);
590   }
591 
592   @Test
addEdge_existingSelfLoopEdgeBetweenSameNodes()593   public void addEdge_existingSelfLoopEdgeBetweenSameNodes() {
594     assume().that(graphIsMutable()).isTrue();
595     assume().that(network.allowsSelfLoops()).isTrue();
596 
597     addEdge(N1, N1, E11);
598     ImmutableSet<String> edges = ImmutableSet.copyOf(network.edges());
599     assertThat(networkAsMutableNetwork.addEdge(N1, N1, E11)).isFalse();
600     assertThat(network.edges()).containsExactlyElementsIn(edges);
601   }
602 
603   @Test
addEdge_existingEdgeBetweenDifferentNodes_selfLoops()604   public void addEdge_existingEdgeBetweenDifferentNodes_selfLoops() {
605     assume().that(graphIsMutable()).isTrue();
606     assume().that(network.allowsSelfLoops()).isTrue();
607 
608     addEdge(N1, N1, E11);
609     IllegalArgumentException e =
610         assertThrows(
611             IllegalArgumentException.class, () -> networkAsMutableNetwork.addEdge(N1, N2, E11));
612     assertThat(e.getMessage()).contains(ERROR_REUSE_EDGE);
613     e =
614         assertThrows(
615             IllegalArgumentException.class, () -> networkAsMutableNetwork.addEdge(N2, N2, E11));
616     assertThat(e.getMessage()).contains(ERROR_REUSE_EDGE);
617     addEdge(N1, N2, E12);
618     e =
619         assertThrows(
620             IllegalArgumentException.class, () -> networkAsMutableNetwork.addEdge(N1, N1, E12));
621     assertThat(e.getMessage()).contains(ERROR_REUSE_EDGE);
622   }
623 
624   @Test
addEdge_parallelSelfLoopEdge_notAllowed()625   public void addEdge_parallelSelfLoopEdge_notAllowed() {
626     assume().that(graphIsMutable()).isTrue();
627     assume().that(network.allowsSelfLoops()).isTrue();
628     assume().that(network.allowsParallelEdges()).isFalse();
629 
630     addEdge(N1, N1, E11);
631     IllegalArgumentException e =
632         assertThrows(
633             IllegalArgumentException.class,
634             () -> networkAsMutableNetwork.addEdge(N1, N1, EDGE_NOT_IN_GRAPH));
635     assertThat(e.getMessage()).contains(ERROR_PARALLEL_EDGE);
636   }
637 
638   @Test
addEdge_parallelSelfLoopEdge_allowsParallelEdges()639   public void addEdge_parallelSelfLoopEdge_allowsParallelEdges() {
640     assume().that(graphIsMutable()).isTrue();
641     assume().that(network.allowsSelfLoops()).isTrue();
642     assume().that(network.allowsParallelEdges()).isTrue();
643 
644     assertTrue(networkAsMutableNetwork.addEdge(N1, N1, E11));
645     assertTrue(networkAsMutableNetwork.addEdge(N1, N1, E11_A));
646     assertThat(network.edgesConnecting(N1, N1)).containsExactly(E11, E11_A);
647   }
648 
649   @Test
removeNode_existingNodeWithSelfLoopEdge()650   public void removeNode_existingNodeWithSelfLoopEdge() {
651     assume().that(graphIsMutable()).isTrue();
652     assume().that(network.allowsSelfLoops()).isTrue();
653 
654     addNode(N1);
655     addEdge(N1, N1, E11);
656     assertThat(networkAsMutableNetwork.removeNode(N1)).isTrue();
657     assertThat(network.nodes()).isEmpty();
658     assertThat(network.edges()).doesNotContain(E11);
659   }
660 
661   @Test
removeEdge_existingSelfLoopEdge()662   public void removeEdge_existingSelfLoopEdge() {
663     assume().that(graphIsMutable()).isTrue();
664     assume().that(network.allowsSelfLoops()).isTrue();
665 
666     addEdge(N1, N1, E11);
667     assertThat(networkAsMutableNetwork.removeEdge(E11)).isTrue();
668     assertThat(network.edges()).doesNotContain(E11);
669     assertThat(network.edgesConnecting(N1, N1)).isEmpty();
670   }
671 }
672