• 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.TestUtil.ERROR_NODE_NOT_IN_GRAPH;
20 import static com.google.common.graph.TestUtil.assertEdgeNotInGraphErrorMessage;
21 import static com.google.common.graph.TestUtil.assertNodeNotInGraphErrorMessage;
22 import static com.google.common.graph.TestUtil.assertStronglyEquivalent;
23 import static com.google.common.graph.TestUtil.sanityCheckSet;
24 import static com.google.common.truth.Truth.assertThat;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 
29 import com.google.common.collect.ImmutableSet;
30 import com.google.common.collect.Sets;
31 import com.google.errorprone.annotations.CanIgnoreReturnValue;
32 import java.util.Set;
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Test;
36 
37 /**
38  * Abstract base class for testing implementations of {@link Network} interface. Network instances
39  * created for testing should have Integer node and String edge objects.
40  *
41  * <p>Test cases that should be handled similarly in any graph implementation are included in this
42  * class. For example, testing that {@code nodes()} method returns the set of the nodes in the
43  * graph. The following test cases are left for the subclasses to handle:
44  *
45  * <ul>
46  *   <li>Test cases related to whether the graph is directed, undirected, mutable, or immutable.
47  *   <li>Test cases related to the specific implementation of the {@link Network} interface.
48  * </ul>
49  *
50  * TODO(user): Make this class generic (using <N, E>) for all node and edge types.
51  * TODO(user): Differentiate between directed and undirected edge strings.
52  */
53 public abstract class AbstractNetworkTest {
54   MutableNetwork<Integer, String> network;
55   static final Integer N1 = 1;
56   static final Integer N2 = 2;
57   static final Integer N3 = 3;
58   static final Integer N4 = 4;
59   static final Integer N5 = 5;
60   static final Integer NODE_NOT_IN_GRAPH = 1000;
61 
62   static final String E11 = "1-1";
63   static final String E11_A = "1-1a";
64   static final String E12 = "1-2";
65   static final String E12_A = "1-2a";
66   static final String E12_B = "1-2b";
67   static final String E21 = "2-1";
68   static final String E13 = "1-3";
69   static final String E14 = "1-4";
70   static final String E23 = "2-3";
71   static final String E31 = "3-1";
72   static final String E34 = "3-4";
73   static final String E41 = "4-1";
74   static final String E15 = "1-5";
75   static final String EDGE_NOT_IN_GRAPH = "edgeNotInGraph";
76 
77   // TODO(user): Consider separating Strings that we've defined here to capture
78   // identifiable substrings of expected error messages, from Strings that we've defined
79   // here to provide error messages.
80   // TODO(user): Some Strings used in the subclasses can be added as static Strings
81   // here too.
82   static final String ERROR_PARALLEL_EDGE = "connected by a different edge";
83   static final String ERROR_REUSE_EDGE = "it cannot be reused to connect";
84   static final String ERROR_MODIFIABLE_COLLECTION =
85       "Collection returned is unexpectedly modifiable";
86   static final String ERROR_SELF_LOOP = "self-loops are not allowed";
87   static final String ERROR_EDGE_NOT_IN_GRAPH =
88       "Should not be allowed to pass an edge that is not an element of the graph.";
89   static final String ERROR_ADDED_SELF_LOOP = "Should not be allowed to add a self-loop edge.";
90   static final String ERROR_ADDED_PARALLEL_EDGE = "Should not be allowed to add a parallel edge.";
91   static final String ERROR_ADDED_EXISTING_EDGE =
92       "Reusing an existing edge to connect different nodes succeeded";
93 
94   /** Creates and returns an instance of the graph to be tested. */
createGraph()95   public abstract MutableNetwork<Integer, String> createGraph();
96 
97   /**
98    * A proxy method that adds the node {@code n} to the graph being tested. In case of Immutable
99    * graph implementations, this method should add {@code n} to the graph builder and build a new
100    * graph with the current builder state.
101    *
102    * @return {@code true} iff the graph was modified as a result of this call
103    */
104   @CanIgnoreReturnValue
addNode(Integer n)105   protected boolean addNode(Integer n) {
106     return network.addNode(n);
107   }
108 
109   /**
110    * A proxy method that adds the edge {@code e} to the graph being tested. In case of Immutable
111    * graph implementations, this method should add {@code e} to the graph builder and build a new
112    * graph with the current builder state.
113    *
114    * <p>This method should be used in tests of specific implementations if you want to ensure
115    * uniform behavior (including side effects) with how edges are added elsewhere in the tests. For
116    * example, the existing implementations of this method explicitly add the supplied nodes to the
117    * graph, and then call {@code graph.addEdge()} to connect the edge to the nodes; this is not part
118    * of the contract of {@code graph.addEdge()} and is done for convenience. In cases where you want
119    * to avoid such side effects (e.g., if you're testing what happens in your implementation if you
120    * add an edge whose end-points don't already exist in the graph), you should <b>not</b> use this
121    * method.
122    *
123    * <p>TODO(user): remove the addNode() calls, that's now contractually guaranteed
124    *
125    * @return {@code true} iff the graph was modified as a result of this call
126    */
127   @CanIgnoreReturnValue
addEdge(Integer n1, Integer n2, String e)128   protected boolean addEdge(Integer n1, Integer n2, String e) {
129     network.addNode(n1);
130     network.addNode(n2);
131     return network.addEdge(n1, n2, e);
132   }
133 
addEdge(EndpointPair<Integer> endpoints, String e)134   protected boolean addEdge(EndpointPair<Integer> endpoints, String e) {
135     network.addNode(endpoints.nodeU());
136     network.addNode(endpoints.nodeV());
137     return network.addEdge(endpoints, e);
138   }
139 
140   @Before
init()141   public void init() {
142     network = createGraph();
143   }
144 
145   @After
validateNetworkState()146   public void validateNetworkState() {
147     validateNetwork(network);
148   }
149 
validateNetwork(Network<N, E> network)150   static <N, E> void validateNetwork(Network<N, E> network) {
151     assertStronglyEquivalent(network, Graphs.copyOf(network));
152     assertStronglyEquivalent(network, ImmutableNetwork.copyOf(network));
153 
154     String networkString = network.toString();
155     assertThat(networkString).contains("isDirected: " + network.isDirected());
156     assertThat(networkString).contains("allowsParallelEdges: " + network.allowsParallelEdges());
157     assertThat(networkString).contains("allowsSelfLoops: " + network.allowsSelfLoops());
158 
159     int nodeStart = networkString.indexOf("nodes:");
160     int edgeStart = networkString.indexOf("edges:");
161     String nodeString = networkString.substring(nodeStart, edgeStart);
162     String edgeString = networkString.substring(edgeStart);
163 
164     Graph<N> asGraph = network.asGraph();
165     AbstractGraphTest.validateGraph(asGraph);
166     assertThat(network.nodes()).isEqualTo(asGraph.nodes());
167     assertThat(network.edges().size()).isAtLeast(asGraph.edges().size());
168     assertThat(network.nodeOrder()).isEqualTo(asGraph.nodeOrder());
169     assertThat(network.isDirected()).isEqualTo(asGraph.isDirected());
170     assertThat(network.allowsSelfLoops()).isEqualTo(asGraph.allowsSelfLoops());
171 
172     for (E edge : sanityCheckSet(network.edges())) {
173       // TODO(b/27817069): Consider verifying the edge's incident nodes in the string.
174       assertThat(edgeString).contains(edge.toString());
175 
176       EndpointPair<N> endpointPair = network.incidentNodes(edge);
177       N nodeU = endpointPair.nodeU();
178       N nodeV = endpointPair.nodeV();
179       assertThat(asGraph.edges()).contains(EndpointPair.of(network, nodeU, nodeV));
180       assertThat(network.edgesConnecting(nodeU, nodeV)).contains(edge);
181       assertThat(network.successors(nodeU)).contains(nodeV);
182       assertThat(network.adjacentNodes(nodeU)).contains(nodeV);
183       assertThat(network.outEdges(nodeU)).contains(edge);
184       assertThat(network.incidentEdges(nodeU)).contains(edge);
185       assertThat(network.predecessors(nodeV)).contains(nodeU);
186       assertThat(network.adjacentNodes(nodeV)).contains(nodeU);
187       assertThat(network.inEdges(nodeV)).contains(edge);
188       assertThat(network.incidentEdges(nodeV)).contains(edge);
189 
190       for (N incidentNode : network.incidentNodes(edge)) {
191         assertThat(network.nodes()).contains(incidentNode);
192         for (E adjacentEdge : network.incidentEdges(incidentNode)) {
193           assertTrue(
194               edge.equals(adjacentEdge) || network.adjacentEdges(edge).contains(adjacentEdge));
195         }
196       }
197     }
198 
199     for (N node : sanityCheckSet(network.nodes())) {
200       assertThat(nodeString).contains(node.toString());
201 
202       assertThat(network.adjacentNodes(node)).isEqualTo(asGraph.adjacentNodes(node));
203       assertThat(network.predecessors(node)).isEqualTo(asGraph.predecessors(node));
204       assertThat(network.successors(node)).isEqualTo(asGraph.successors(node));
205 
206       int selfLoopCount = network.edgesConnecting(node, node).size();
207       assertThat(network.incidentEdges(node).size() + selfLoopCount)
208           .isEqualTo(network.degree(node));
209 
210       if (network.isDirected()) {
211         assertThat(network.incidentEdges(node).size() + selfLoopCount)
212             .isEqualTo(network.inDegree(node) + network.outDegree(node));
213         assertThat(network.inEdges(node)).hasSize(network.inDegree(node));
214         assertThat(network.outEdges(node)).hasSize(network.outDegree(node));
215       } else {
216         assertThat(network.predecessors(node)).isEqualTo(network.adjacentNodes(node));
217         assertThat(network.successors(node)).isEqualTo(network.adjacentNodes(node));
218         assertThat(network.inEdges(node)).isEqualTo(network.incidentEdges(node));
219         assertThat(network.outEdges(node)).isEqualTo(network.incidentEdges(node));
220         assertThat(network.inDegree(node)).isEqualTo(network.degree(node));
221         assertThat(network.outDegree(node)).isEqualTo(network.degree(node));
222       }
223 
224       for (N otherNode : network.nodes()) {
225         Set<E> edgesConnecting = sanityCheckSet(network.edgesConnecting(node, otherNode));
226         switch (edgesConnecting.size()) {
227           case 0:
228             assertThat(network.edgeConnectingOrNull(node, otherNode)).isNull();
229             assertThat(network.edgeConnecting(node, otherNode).isPresent()).isFalse();
230             assertThat(network.hasEdgeConnecting(node, otherNode)).isFalse();
231             break;
232           case 1:
233             E edge = edgesConnecting.iterator().next();
234             assertThat(network.edgeConnectingOrNull(node, otherNode)).isEqualTo(edge);
235             assertThat(network.edgeConnecting(node, otherNode).get()).isEqualTo(edge);
236             assertThat(network.hasEdgeConnecting(node, otherNode)).isTrue();
237             break;
238           default:
239             assertThat(network.hasEdgeConnecting(node, otherNode)).isTrue();
240             try {
241               network.edgeConnectingOrNull(node, otherNode);
242               fail();
243             } catch (IllegalArgumentException expected) {
244             }
245             try {
246               network.edgeConnecting(node, otherNode);
247               fail();
248             } catch (IllegalArgumentException expected) {
249             }
250         }
251 
252         boolean isSelfLoop = node.equals(otherNode);
253         boolean connected = !edgesConnecting.isEmpty();
254         if (network.isDirected() || !isSelfLoop) {
255           assertThat(edgesConnecting)
256               .isEqualTo(Sets.intersection(network.outEdges(node), network.inEdges(otherNode)));
257         }
258         if (!network.allowsParallelEdges()) {
259           assertThat(edgesConnecting.size()).isAtMost(1);
260         }
261         if (!network.allowsSelfLoops() && isSelfLoop) {
262           assertThat(connected).isFalse();
263         }
264 
265         assertThat(network.successors(node).contains(otherNode)).isEqualTo(connected);
266         assertThat(network.predecessors(otherNode).contains(node)).isEqualTo(connected);
267         for (E edge : edgesConnecting) {
268           assertThat(network.incidentNodes(edge))
269               .isEqualTo(EndpointPair.of(network, node, otherNode));
270           assertThat(network.outEdges(node)).contains(edge);
271           assertThat(network.inEdges(otherNode)).contains(edge);
272         }
273       }
274 
275       for (N adjacentNode : sanityCheckSet(network.adjacentNodes(node))) {
276         assertTrue(
277             network.predecessors(node).contains(adjacentNode)
278                 || network.successors(node).contains(adjacentNode));
279         assertTrue(
280             !network.edgesConnecting(node, adjacentNode).isEmpty()
281                 || !network.edgesConnecting(adjacentNode, node).isEmpty());
282       }
283 
284       for (N predecessor : sanityCheckSet(network.predecessors(node))) {
285         assertThat(network.successors(predecessor)).contains(node);
286         assertThat(network.edgesConnecting(predecessor, node)).isNotEmpty();
287       }
288 
289       for (N successor : sanityCheckSet(network.successors(node))) {
290         assertThat(network.predecessors(successor)).contains(node);
291         assertThat(network.edgesConnecting(node, successor)).isNotEmpty();
292       }
293 
294       for (E incidentEdge : sanityCheckSet(network.incidentEdges(node))) {
295         assertTrue(
296             network.inEdges(node).contains(incidentEdge)
297                 || network.outEdges(node).contains(incidentEdge));
298         assertThat(network.edges()).contains(incidentEdge);
299         assertThat(network.incidentNodes(incidentEdge)).contains(node);
300       }
301 
302       for (E inEdge : sanityCheckSet(network.inEdges(node))) {
303         assertThat(network.incidentEdges(node)).contains(inEdge);
304         assertThat(network.outEdges(network.incidentNodes(inEdge).adjacentNode(node)))
305             .contains(inEdge);
306         if (network.isDirected()) {
307           assertThat(network.incidentNodes(inEdge).target()).isEqualTo(node);
308         }
309       }
310 
311       for (E outEdge : sanityCheckSet(network.outEdges(node))) {
312         assertThat(network.incidentEdges(node)).contains(outEdge);
313         assertThat(network.inEdges(network.incidentNodes(outEdge).adjacentNode(node)))
314             .contains(outEdge);
315         if (network.isDirected()) {
316           assertThat(network.incidentNodes(outEdge).source()).isEqualTo(node);
317         }
318       }
319     }
320   }
321 
322   /**
323    * Verifies that the {@code Set} returned by {@code nodes} has the expected mutability property
324    * (see the {@code Network} documentation for more information).
325    */
326   @Test
nodes_checkReturnedSetMutability()327   public abstract void nodes_checkReturnedSetMutability();
328 
329   /**
330    * Verifies that the {@code Set} returned by {@code edges} has the expected mutability property
331    * (see the {@code Network} documentation for more information).
332    */
333   @Test
edges_checkReturnedSetMutability()334   public abstract void edges_checkReturnedSetMutability();
335 
336   /**
337    * Verifies that the {@code Set} returned by {@code incidentEdges} has the expected mutability
338    * property (see the {@code Network} documentation for more information).
339    */
340   @Test
incidentEdges_checkReturnedSetMutability()341   public abstract void incidentEdges_checkReturnedSetMutability();
342 
343   /**
344    * Verifies that the {@code Set} returned by {@code adjacentNodes} has the expected mutability
345    * property (see the {@code Network} documentation for more information).
346    */
347   @Test
adjacentNodes_checkReturnedSetMutability()348   public abstract void adjacentNodes_checkReturnedSetMutability();
349 
350   /**
351    * Verifies that the {@code Set} returned by {@code adjacentEdges} has the expected mutability
352    * property (see the {@code Network} documentation for more information).
353    */
354   @Test
adjacentEdges_checkReturnedSetMutability()355   public abstract void adjacentEdges_checkReturnedSetMutability();
356 
357   /**
358    * Verifies that the {@code Set} returned by {@code edgesConnecting} has the expected mutability
359    * property (see the {@code Network} documentation for more information).
360    */
361   @Test
edgesConnecting_checkReturnedSetMutability()362   public abstract void edgesConnecting_checkReturnedSetMutability();
363 
364   /**
365    * Verifies that the {@code Set} returned by {@code inEdges} has the expected mutability property
366    * (see the {@code Network} documentation for more information).
367    */
368   @Test
inEdges_checkReturnedSetMutability()369   public abstract void inEdges_checkReturnedSetMutability();
370 
371   /**
372    * Verifies that the {@code Set} returned by {@code outEdges} has the expected mutability property
373    * (see the {@code Network} documentation for more information).
374    */
375   @Test
outEdges_checkReturnedSetMutability()376   public abstract void outEdges_checkReturnedSetMutability();
377 
378   /**
379    * Verifies that the {@code Set} returned by {@code predecessors} has the expected mutability
380    * property (see the {@code Network} documentation for more information).
381    */
382   @Test
predecessors_checkReturnedSetMutability()383   public abstract void predecessors_checkReturnedSetMutability();
384 
385   /**
386    * Verifies that the {@code Set} returned by {@code successors} has the expected mutability
387    * property (see the {@code Network} documentation for more information).
388    */
389   @Test
successors_checkReturnedSetMutability()390   public abstract void successors_checkReturnedSetMutability();
391 
392   @Test
nodes_oneNode()393   public void nodes_oneNode() {
394     addNode(N1);
395     assertThat(network.nodes()).containsExactly(N1);
396   }
397 
398   @Test
nodes_noNodes()399   public void nodes_noNodes() {
400     assertThat(network.nodes()).isEmpty();
401   }
402 
403   @Test
edges_oneEdge()404   public void edges_oneEdge() {
405     addEdge(N1, N2, E12);
406     assertThat(network.edges()).containsExactly(E12);
407   }
408 
409   @Test
edges_noEdges()410   public void edges_noEdges() {
411     assertThat(network.edges()).isEmpty();
412     // Network with no edges, given disconnected nodes
413     addNode(N1);
414     addNode(N2);
415     assertThat(network.edges()).isEmpty();
416   }
417 
418   @Test
incidentEdges_oneEdge()419   public void incidentEdges_oneEdge() {
420     addEdge(N1, N2, E12);
421     assertThat(network.incidentEdges(N2)).containsExactly(E12);
422     assertThat(network.incidentEdges(N1)).containsExactly(E12);
423   }
424 
425   @Test
incidentEdges_isolatedNode()426   public void incidentEdges_isolatedNode() {
427     addNode(N1);
428     assertThat(network.incidentEdges(N1)).isEmpty();
429   }
430 
431   @Test
incidentEdges_nodeNotInGraph()432   public void incidentEdges_nodeNotInGraph() {
433     try {
434       network.incidentEdges(NODE_NOT_IN_GRAPH);
435       fail(ERROR_NODE_NOT_IN_GRAPH);
436     } catch (IllegalArgumentException e) {
437       assertNodeNotInGraphErrorMessage(e);
438     }
439   }
440 
441   @Test
incidentNodes_oneEdge()442   public void incidentNodes_oneEdge() {
443     addEdge(N1, N2, E12);
444     assertThat(network.incidentNodes(E12)).containsExactly(N1, N2);
445   }
446 
447   @Test
incidentNodes_edgeNotInGraph()448   public void incidentNodes_edgeNotInGraph() {
449     try {
450       network.incidentNodes(EDGE_NOT_IN_GRAPH);
451       fail(ERROR_EDGE_NOT_IN_GRAPH);
452     } catch (IllegalArgumentException e) {
453       assertEdgeNotInGraphErrorMessage(e);
454     }
455   }
456 
457   @Test
adjacentNodes_oneEdge()458   public void adjacentNodes_oneEdge() {
459     addEdge(N1, N2, E12);
460     assertThat(network.adjacentNodes(N1)).containsExactly(N2);
461     assertThat(network.adjacentNodes(N2)).containsExactly(N1);
462   }
463 
464   @Test
adjacentNodes_noAdjacentNodes()465   public void adjacentNodes_noAdjacentNodes() {
466     addNode(N1);
467     assertThat(network.adjacentNodes(N1)).isEmpty();
468   }
469 
470   @Test
adjacentNodes_nodeNotInGraph()471   public void adjacentNodes_nodeNotInGraph() {
472     try {
473       network.adjacentNodes(NODE_NOT_IN_GRAPH);
474       fail(ERROR_NODE_NOT_IN_GRAPH);
475     } catch (IllegalArgumentException e) {
476       assertNodeNotInGraphErrorMessage(e);
477     }
478   }
479 
480   @Test
adjacentEdges_bothEndpoints()481   public void adjacentEdges_bothEndpoints() {
482     addEdge(N1, N2, E12);
483     addEdge(N2, N3, E23);
484     addEdge(N3, N1, E31);
485     addEdge(N3, N4, E34);
486     assertThat(network.adjacentEdges(E12)).containsExactly(E31, E23);
487   }
488 
489   @Test
adjacentEdges_noAdjacentEdges()490   public void adjacentEdges_noAdjacentEdges() {
491     addEdge(N1, N2, E12);
492     addEdge(N3, N4, E34);
493     assertThat(network.adjacentEdges(E12)).isEmpty();
494   }
495 
496   @Test
adjacentEdges_edgeNotInGraph()497   public void adjacentEdges_edgeNotInGraph() {
498     try {
499       network.adjacentEdges(EDGE_NOT_IN_GRAPH);
500       fail(ERROR_EDGE_NOT_IN_GRAPH);
501     } catch (IllegalArgumentException e) {
502       assertEdgeNotInGraphErrorMessage(e);
503     }
504   }
505 
506   @Test
edgesConnecting_disconnectedNodes()507   public void edgesConnecting_disconnectedNodes() {
508     addNode(N1);
509     addNode(N2);
510     assertThat(network.edgesConnecting(N1, N2)).isEmpty();
511   }
512 
513   @Test
edgesConnecting_nodesNotInGraph()514   public void edgesConnecting_nodesNotInGraph() {
515     addNode(N1);
516     addNode(N2);
517     try {
518       network.edgesConnecting(N1, NODE_NOT_IN_GRAPH);
519       fail(ERROR_NODE_NOT_IN_GRAPH);
520     } catch (IllegalArgumentException e) {
521       assertNodeNotInGraphErrorMessage(e);
522     }
523     try {
524       network.edgesConnecting(NODE_NOT_IN_GRAPH, N2);
525       fail(ERROR_NODE_NOT_IN_GRAPH);
526     } catch (IllegalArgumentException e) {
527       assertNodeNotInGraphErrorMessage(e);
528     }
529     try {
530       network.edgesConnecting(NODE_NOT_IN_GRAPH, NODE_NOT_IN_GRAPH);
531       fail(ERROR_NODE_NOT_IN_GRAPH);
532     } catch (IllegalArgumentException e) {
533       assertNodeNotInGraphErrorMessage(e);
534     }
535   }
536 
537   @Test
inEdges_noInEdges()538   public void inEdges_noInEdges() {
539     addNode(N1);
540     assertThat(network.inEdges(N1)).isEmpty();
541   }
542 
543   @Test
inEdges_nodeNotInGraph()544   public void inEdges_nodeNotInGraph() {
545     try {
546       network.inEdges(NODE_NOT_IN_GRAPH);
547       fail(ERROR_NODE_NOT_IN_GRAPH);
548     } catch (IllegalArgumentException e) {
549       assertNodeNotInGraphErrorMessage(e);
550     }
551   }
552 
553   @Test
outEdges_noOutEdges()554   public void outEdges_noOutEdges() {
555     addNode(N1);
556     assertThat(network.outEdges(N1)).isEmpty();
557   }
558 
559   @Test
outEdges_nodeNotInGraph()560   public void outEdges_nodeNotInGraph() {
561     try {
562       network.outEdges(NODE_NOT_IN_GRAPH);
563       fail(ERROR_NODE_NOT_IN_GRAPH);
564     } catch (IllegalArgumentException e) {
565       assertNodeNotInGraphErrorMessage(e);
566     }
567   }
568 
569   @Test
predecessors_noPredecessors()570   public void predecessors_noPredecessors() {
571     addNode(N1);
572     assertThat(network.predecessors(N1)).isEmpty();
573   }
574 
575   @Test
predecessors_nodeNotInGraph()576   public void predecessors_nodeNotInGraph() {
577     try {
578       network.predecessors(NODE_NOT_IN_GRAPH);
579       fail(ERROR_NODE_NOT_IN_GRAPH);
580     } catch (IllegalArgumentException e) {
581       assertNodeNotInGraphErrorMessage(e);
582     }
583   }
584 
585   @Test
successors_noSuccessors()586   public void successors_noSuccessors() {
587     addNode(N1);
588     assertThat(network.successors(N1)).isEmpty();
589   }
590 
591   @Test
successors_nodeNotInGraph()592   public void successors_nodeNotInGraph() {
593     try {
594       network.successors(NODE_NOT_IN_GRAPH);
595       fail(ERROR_NODE_NOT_IN_GRAPH);
596     } catch (IllegalArgumentException e) {
597       assertNodeNotInGraphErrorMessage(e);
598     }
599   }
600 
601   @Test
addNode_newNode()602   public void addNode_newNode() {
603     assertTrue(addNode(N1));
604     assertThat(network.nodes()).contains(N1);
605   }
606 
607   @Test
addNode_existingNode()608   public void addNode_existingNode() {
609     addNode(N1);
610     ImmutableSet<Integer> nodes = ImmutableSet.copyOf(network.nodes());
611     assertFalse(addNode(N1));
612     assertThat(network.nodes()).containsExactlyElementsIn(nodes);
613   }
614 
615   @Test
removeNode_existingNode()616   public void removeNode_existingNode() {
617     addEdge(N1, N2, E12);
618     addEdge(N4, N1, E41);
619     assertTrue(network.removeNode(N1));
620     assertFalse(network.removeNode(N1));
621     assertThat(network.nodes()).containsExactly(N2, N4);
622     assertThat(network.edges()).doesNotContain(E12);
623     assertThat(network.edges()).doesNotContain(E41);
624   }
625 
626   @Test
removeNode_nodeNotPresent()627   public void removeNode_nodeNotPresent() {
628     addNode(N1);
629     ImmutableSet<Integer> nodes = ImmutableSet.copyOf(network.nodes());
630     assertFalse(network.removeNode(NODE_NOT_IN_GRAPH));
631     assertThat(network.nodes()).containsExactlyElementsIn(nodes);
632   }
633 
634   @Test
removeNode_queryAfterRemoval()635   public void removeNode_queryAfterRemoval() {
636     addNode(N1);
637     @SuppressWarnings("unused")
638     Set<Integer> unused = network.adjacentNodes(N1); // ensure cache (if any) is populated
639     assertTrue(network.removeNode(N1));
640     try {
641       network.adjacentNodes(N1);
642       fail(ERROR_NODE_NOT_IN_GRAPH);
643     } catch (IllegalArgumentException e) {
644       assertNodeNotInGraphErrorMessage(e);
645     }
646   }
647 
648   @Test
removeEdge_existingEdge()649   public void removeEdge_existingEdge() {
650     addEdge(N1, N2, E12);
651     assertTrue(network.removeEdge(E12));
652     assertFalse(network.removeEdge(E12));
653     assertThat(network.edges()).doesNotContain(E12);
654     assertThat(network.edgesConnecting(N1, N2)).isEmpty();
655   }
656 
657   @Test
removeEdge_oneOfMany()658   public void removeEdge_oneOfMany() {
659     addEdge(N1, N2, E12);
660     addEdge(N1, N3, E13);
661     addEdge(N1, N4, E14);
662     assertThat(network.edges()).containsExactly(E12, E13, E14);
663     assertTrue(network.removeEdge(E13));
664     assertThat(network.edges()).containsExactly(E12, E14);
665   }
666 
667   @Test
removeEdge_edgeNotPresent()668   public void removeEdge_edgeNotPresent() {
669     addEdge(N1, N2, E12);
670     ImmutableSet<String> edges = ImmutableSet.copyOf(network.edges());
671     assertFalse(network.removeEdge(EDGE_NOT_IN_GRAPH));
672     assertThat(network.edges()).containsExactlyElementsIn(edges);
673   }
674 
675   @Test
removeEdge_queryAfterRemoval()676   public void removeEdge_queryAfterRemoval() {
677     addEdge(N1, N2, E12);
678     @SuppressWarnings("unused")
679     EndpointPair<Integer> unused = network.incidentNodes(E12); // ensure cache (if any) is populated
680     assertTrue(network.removeEdge(E12));
681     try {
682       network.incidentNodes(E12);
683       fail(ERROR_EDGE_NOT_IN_GRAPH);
684     } catch (IllegalArgumentException e) {
685       assertEdgeNotInGraphErrorMessage(e);
686     }
687   }
688 }
689