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