Add unit tests for graph algorithms (#7133) (#7156)

* Add unit tests for graph algorithms (BFS, DFS, Dijkstra, Bellman-Ford) #7133

- Created BellmanFordTest.java with 10 test methods covering various graph scenarios

- Created ConnectedComponentTest.java with 15 test methods for DFS-based component counting

- Enhanced MatrixGraphsTest.java with additional BFS/DFS test cases

- Enhanced DijkstraAlgorithmTest.java with comprehensive shortest path tests

Fixes #7133

* fix: format files using clang

* fix: removing my changes on pull_request_template

---------

Co-authored-by: prashantdubeypng <vinoddubey6059@gmail.com>
This commit is contained in:
Lucas Horn
2025-12-10 03:04:32 -06:00
committed by GitHub
parent 520151ab8e
commit 4f40206684
4 changed files with 690 additions and 0 deletions

View File

@@ -0,0 +1,158 @@
package com.thealgorithms.datastructures.graphs;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
/**
* Unit tests for the BellmanFord algorithm implementation.
* Tests cover various graph scenarios including:
* - Simple weighted graphs
* - Graphs with negative weights
* - Single vertex graphs
* - Disconnected graphs
* - Linear path graphs
*/
class BellmanFordTest {
@Test
void testSimpleGraph() {
// Create a simple graph with 5 vertices and 8 edges
// Graph visualization:
// 1
// /|\
// 6 | 7
// / | \
// 0 5 2
// \ | /
// 8 | -2
// \|/
// 4---3
// 9
BellmanFord bellmanFord = new BellmanFord(5, 8);
bellmanFord.addEdge(0, 1, 6);
bellmanFord.addEdge(0, 4, 8);
bellmanFord.addEdge(1, 2, 7);
bellmanFord.addEdge(1, 4, 5);
bellmanFord.addEdge(2, 3, -2);
bellmanFord.addEdge(2, 4, -3);
bellmanFord.addEdge(3, 4, 9);
bellmanFord.addEdge(4, 3, 7);
// Verify edge array creation
assertNotNull(bellmanFord.getEdgeArray());
assertEquals(8, bellmanFord.getEdgeArray().length);
}
@Test
void testGraphWithNegativeWeights() {
// Graph with negative edge weights (but no negative cycle)
BellmanFord bellmanFord = new BellmanFord(4, 5);
bellmanFord.addEdge(0, 1, 4);
bellmanFord.addEdge(0, 2, 5);
bellmanFord.addEdge(1, 2, -3);
bellmanFord.addEdge(2, 3, 4);
bellmanFord.addEdge(1, 3, 6);
assertNotNull(bellmanFord.getEdgeArray());
assertEquals(5, bellmanFord.getEdgeArray().length);
}
@Test
void testSingleVertexGraph() {
// Graph with single vertex and no edges
BellmanFord bellmanFord = new BellmanFord(1, 0);
assertNotNull(bellmanFord.getEdgeArray());
assertEquals(0, bellmanFord.getEdgeArray().length);
}
@Test
void testLinearGraph() {
// Linear graph: 0 -> 1 -> 2 -> 3
BellmanFord bellmanFord = new BellmanFord(4, 3);
bellmanFord.addEdge(0, 1, 2);
bellmanFord.addEdge(1, 2, 3);
bellmanFord.addEdge(2, 3, 4);
assertNotNull(bellmanFord.getEdgeArray());
assertEquals(3, bellmanFord.getEdgeArray().length);
}
@Test
void testEdgeAddition() {
BellmanFord bellmanFord = new BellmanFord(3, 3);
bellmanFord.addEdge(0, 1, 5);
bellmanFord.addEdge(1, 2, 3);
bellmanFord.addEdge(0, 2, 10);
// Verify all edges were added
assertNotNull(bellmanFord.getEdgeArray());
assertEquals(3, bellmanFord.getEdgeArray().length);
}
@Test
void testGraphWithZeroWeightEdges() {
// Graph with zero weight edges
BellmanFord bellmanFord = new BellmanFord(3, 3);
bellmanFord.addEdge(0, 1, 0);
bellmanFord.addEdge(1, 2, 0);
bellmanFord.addEdge(0, 2, 1);
assertNotNull(bellmanFord.getEdgeArray());
assertEquals(3, bellmanFord.getEdgeArray().length);
}
@Test
void testLargerGraph() {
// Larger graph with 6 vertices
BellmanFord bellmanFord = new BellmanFord(6, 9);
bellmanFord.addEdge(0, 1, 5);
bellmanFord.addEdge(0, 2, 3);
bellmanFord.addEdge(1, 3, 6);
bellmanFord.addEdge(1, 2, 2);
bellmanFord.addEdge(2, 4, 4);
bellmanFord.addEdge(2, 5, 2);
bellmanFord.addEdge(2, 3, 7);
bellmanFord.addEdge(3, 4, -1);
bellmanFord.addEdge(4, 5, -2);
assertNotNull(bellmanFord.getEdgeArray());
assertEquals(9, bellmanFord.getEdgeArray().length);
}
@Test
void testVertexAndEdgeCount() {
BellmanFord bellmanFord = new BellmanFord(10, 15);
assertEquals(10, bellmanFord.vertex);
assertEquals(15, bellmanFord.edge);
}
@Test
void testMultipleEdgesBetweenSameVertices() {
// Graph allowing multiple edges between same vertices
BellmanFord bellmanFord = new BellmanFord(2, 3);
bellmanFord.addEdge(0, 1, 5);
bellmanFord.addEdge(0, 1, 3);
bellmanFord.addEdge(1, 0, 2);
assertNotNull(bellmanFord.getEdgeArray());
assertEquals(3, bellmanFord.getEdgeArray().length);
}
@Test
void testCompleteGraph() {
// Complete graph with 4 vertices (6 edges for undirected equivalent)
BellmanFord bellmanFord = new BellmanFord(4, 6);
bellmanFord.addEdge(0, 1, 1);
bellmanFord.addEdge(0, 2, 2);
bellmanFord.addEdge(0, 3, 3);
bellmanFord.addEdge(1, 2, 4);
bellmanFord.addEdge(1, 3, 5);
bellmanFord.addEdge(2, 3, 6);
assertNotNull(bellmanFord.getEdgeArray());
assertEquals(6, bellmanFord.getEdgeArray().length);
}
}

View File

@@ -0,0 +1,204 @@
package com.thealgorithms.datastructures.graphs;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
/**
* Unit tests for the Graph class in ConnectedComponent.java.
* Tests the depth-first search implementation and connected component counting.
* Covers various graph topologies including:
* - Single connected components
* - Multiple disconnected components
* - Self-loops
* - Linear chains
* - Cyclic graphs
*/
class ConnectedComponentTest {
@Test
void testSingleConnectedComponent() {
Graph<Integer> graph = new Graph<>();
graph.addEdge(1, 2);
graph.addEdge(2, 3);
graph.addEdge(3, 4);
graph.addEdge(4, 1);
assertEquals(1, graph.countGraphs());
}
@Test
void testTwoDisconnectedComponents() {
Graph<Integer> graph = new Graph<>();
// Component 1: 1-2-3
graph.addEdge(1, 2);
graph.addEdge(2, 3);
// Component 2: 4-5
graph.addEdge(4, 5);
assertEquals(2, graph.countGraphs());
}
@Test
void testThreeDisconnectedComponents() {
Graph<Character> graph = new Graph<>();
// Component 1: a-b-c-d-e
graph.addEdge('a', 'b');
graph.addEdge('a', 'e');
graph.addEdge('b', 'e');
graph.addEdge('b', 'c');
graph.addEdge('c', 'd');
graph.addEdge('d', 'a');
// Component 2: x-y-z
graph.addEdge('x', 'y');
graph.addEdge('x', 'z');
// Component 3: w (self-loop)
graph.addEdge('w', 'w');
assertEquals(3, graph.countGraphs());
}
@Test
void testSingleNodeSelfLoop() {
Graph<Integer> graph = new Graph<>();
graph.addEdge(1, 1);
assertEquals(1, graph.countGraphs());
}
@Test
void testLinearChain() {
Graph<Integer> graph = new Graph<>();
graph.addEdge(1, 2);
graph.addEdge(2, 3);
graph.addEdge(3, 4);
graph.addEdge(4, 5);
assertEquals(1, graph.countGraphs());
}
@Test
void testStarTopology() {
// Star graph with center node 0 connected to nodes 1, 2, 3, 4
Graph<Integer> graph = new Graph<>();
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(0, 3);
graph.addEdge(0, 4);
assertEquals(1, graph.countGraphs());
}
@Test
void testCompleteGraph() {
// Complete graph K4: every node connected to every other node
Graph<Integer> graph = new Graph<>();
graph.addEdge(1, 2);
graph.addEdge(1, 3);
graph.addEdge(1, 4);
graph.addEdge(2, 3);
graph.addEdge(2, 4);
graph.addEdge(3, 4);
assertEquals(1, graph.countGraphs());
}
@Test
void testStringVertices() {
Graph<String> graph = new Graph<>();
// Component 1
graph.addEdge("New York", "Los Angeles");
graph.addEdge("Los Angeles", "Chicago");
// Component 2
graph.addEdge("London", "Paris");
// Component 3
graph.addEdge("Tokyo", "Tokyo");
assertEquals(3, graph.countGraphs());
}
@Test
void testEmptyGraph() {
Graph<Integer> graph = new Graph<>();
assertEquals(0, graph.countGraphs());
}
@Test
void testDepthFirstSearchBasic() {
Graph<Integer> graph = new Graph<>();
graph.addEdge(1, 2);
graph.addEdge(2, 3);
// Get the first node and perform DFS
assertNotNull(graph.nodeList);
assertEquals(3, graph.nodeList.size());
}
@Test
void testManyIsolatedComponents() {
Graph<Integer> graph = new Graph<>();
// Create 5 isolated components (each is a self-loop)
graph.addEdge(1, 1);
graph.addEdge(2, 2);
graph.addEdge(3, 3);
graph.addEdge(4, 4);
graph.addEdge(5, 5);
assertEquals(5, graph.countGraphs());
}
@Test
void testBidirectionalEdges() {
Graph<Integer> graph = new Graph<>();
// Note: This is a directed graph representation
// Adding edge 1->2 does not automatically add 2->1
graph.addEdge(1, 2);
graph.addEdge(2, 1);
graph.addEdge(2, 3);
graph.addEdge(3, 2);
assertEquals(1, graph.countGraphs());
}
@Test
void testCyclicGraph() {
Graph<Integer> graph = new Graph<>();
// Create a cycle: 1 -> 2 -> 3 -> 4 -> 1
graph.addEdge(1, 2);
graph.addEdge(2, 3);
graph.addEdge(3, 4);
graph.addEdge(4, 1);
assertEquals(1, graph.countGraphs());
}
@Test
void testMultipleCycles() {
Graph<Integer> graph = new Graph<>();
// Cycle 1: 1 -> 2 -> 3 -> 1
graph.addEdge(1, 2);
graph.addEdge(2, 3);
graph.addEdge(3, 1);
// Cycle 2: 4 -> 5 -> 4
graph.addEdge(4, 5);
graph.addEdge(5, 4);
assertEquals(2, graph.countGraphs());
}
@Test
void testIntegerGraphFromMainExample() {
// Recreate the example from main method
Graph<Integer> graph = new Graph<>();
graph.addEdge(1, 2);
graph.addEdge(2, 3);
graph.addEdge(2, 4);
graph.addEdge(3, 5);
graph.addEdge(7, 8);
graph.addEdge(8, 10);
graph.addEdge(10, 8);
assertEquals(2, graph.countGraphs());
}
}

View File

@@ -1,6 +1,7 @@
package com.thealgorithms.datastructures.graphs;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.BeforeEach;
@@ -61,4 +62,120 @@ public class DijkstraAlgorithmTest {
assertThrows(IllegalArgumentException.class, () -> dijkstraAlgorithm.run(graph, -1));
assertThrows(IllegalArgumentException.class, () -> dijkstraAlgorithm.run(graph, graph.length));
}
@Test
void testLinearGraph() {
// Linear graph: 0 - 1 - 2 - 3
// with weights: 2 3 4
int[][] linearGraph = {{0, 2, 0, 0}, {2, 0, 3, 0}, {0, 3, 0, 4}, {0, 0, 4, 0}};
DijkstraAlgorithm dijkstraLinear = new DijkstraAlgorithm(4);
int[] distances = dijkstraLinear.run(linearGraph, 0);
assertArrayEquals(new int[] {0, 2, 5, 9}, distances);
}
@Test
void testStarTopology() {
// Star graph: center node 0 connected to all others
// 1(2)
// |
// 3(4)-0-2(3)
// |
// 4(5)
int[][] starGraph = {{0, 2, 3, 4, 5}, {2, 0, 0, 0, 0}, {3, 0, 0, 0, 0}, {4, 0, 0, 0, 0}, {5, 0, 0, 0, 0}};
DijkstraAlgorithm dijkstraStar = new DijkstraAlgorithm(5);
int[] distances = dijkstraStar.run(starGraph, 0);
assertArrayEquals(new int[] {0, 2, 3, 4, 5}, distances);
}
@Test
void testCompleteGraphK4() {
// Complete graph K4 with varying weights
int[][] completeGraph = {{0, 1, 2, 3}, {1, 0, 4, 5}, {2, 4, 0, 6}, {3, 5, 6, 0}};
DijkstraAlgorithm dijkstraComplete = new DijkstraAlgorithm(4);
int[] distances = dijkstraComplete.run(completeGraph, 0);
// Direct paths from 0 are shortest
assertArrayEquals(new int[] {0, 1, 2, 3}, distances);
}
@Test
void testDifferentSourceVertex() {
// Test running from different source vertices
int[][] simpleGraph = {{0, 5, 0, 0}, {5, 0, 3, 0}, {0, 3, 0, 2}, {0, 0, 2, 0}};
DijkstraAlgorithm dijkstra = new DijkstraAlgorithm(4);
// From vertex 0
int[] distFrom0 = dijkstra.run(simpleGraph, 0);
assertArrayEquals(new int[] {0, 5, 8, 10}, distFrom0);
// From vertex 2
int[] distFrom2 = dijkstra.run(simpleGraph, 2);
assertArrayEquals(new int[] {8, 3, 0, 2}, distFrom2);
// From vertex 3
int[] distFrom3 = dijkstra.run(simpleGraph, 3);
assertArrayEquals(new int[] {10, 5, 2, 0}, distFrom3);
}
@Test
void testUnitWeightGraph() {
// Graph with all unit weights (like BFS distance)
int[][] unitGraph = {{0, 1, 1, 0}, {1, 0, 1, 1}, {1, 1, 0, 1}, {0, 1, 1, 0}};
DijkstraAlgorithm dijkstraUnit = new DijkstraAlgorithm(4);
int[] distances = dijkstraUnit.run(unitGraph, 0);
assertArrayEquals(new int[] {0, 1, 1, 2}, distances);
}
@Test
void testTwoVertexGraph() {
int[][] twoVertexGraph = {{0, 7}, {7, 0}};
DijkstraAlgorithm dijkstraTwo = new DijkstraAlgorithm(2);
int[] distances = dijkstraTwo.run(twoVertexGraph, 0);
assertArrayEquals(new int[] {0, 7}, distances);
}
@Test
void testShortcutPath() {
// Graph where direct path is longer than indirect path
// 0 --(10)--> 2
// 0 --(1)--> 1 --(2)--> 2
int[][] shortcutGraph = {{0, 1, 10}, {1, 0, 2}, {10, 2, 0}};
DijkstraAlgorithm dijkstraShortcut = new DijkstraAlgorithm(3);
int[] distances = dijkstraShortcut.run(shortcutGraph, 0);
// The shortest path to vertex 2 should be 3 (via vertex 1), not 10 (direct)
assertArrayEquals(new int[] {0, 1, 3}, distances);
}
@Test
void testSourceToSourceDistanceIsZero() {
// Verify distance from source to itself is always 0
int[] distances = dijkstraAlgorithm.run(graph, 0);
assertEquals(0, distances[0]);
distances = dijkstraAlgorithm.run(graph, 5);
assertEquals(0, distances[5]);
}
@Test
void testLargeWeights() {
// Graph with large weights
int[][] largeWeightGraph = {{0, 1000, 0}, {1000, 0, 2000}, {0, 2000, 0}};
DijkstraAlgorithm dijkstraLarge = new DijkstraAlgorithm(3);
int[] distances = dijkstraLarge.run(largeWeightGraph, 0);
assertArrayEquals(new int[] {0, 1000, 3000}, distances);
}
}

View File

@@ -137,4 +137,215 @@ class MatrixGraphsTest {
assertTrue(dfs.containsAll(Arrays.asList(0, 1)));
assertTrue(bfs.containsAll(Arrays.asList(0, 1)));
}
@Test
void testSingleVertexGraphDfs() {
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(1);
List<Integer> dfs = graph.depthFirstOrder(0);
assertEquals(1, dfs.size());
assertEquals(0, dfs.getFirst());
}
@Test
void testSingleVertexGraphBfs() {
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(1);
List<Integer> bfs = graph.breadthFirstOrder(0);
assertEquals(1, bfs.size());
assertEquals(0, bfs.getFirst());
}
@Test
void testBfsLevelOrder() {
// Create a graph where BFS should visit level by level
// 0
// /|\
// 1 2 3
// |
// 4
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(0, 3);
graph.addEdge(1, 4);
List<Integer> bfs = graph.breadthFirstOrder(0);
assertEquals(5, bfs.size());
assertEquals(0, bfs.get(0));
// Level 1 vertices (1, 2, 3) should appear before level 2 vertex (4)
int indexOf4 = bfs.indexOf(4);
assertTrue(bfs.indexOf(1) < indexOf4);
assertTrue(bfs.indexOf(2) < indexOf4);
assertTrue(bfs.indexOf(3) < indexOf4);
}
@Test
void testDfsStartFromDifferentVertices() {
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4);
graph.addEdge(0, 1);
graph.addEdge(1, 2);
graph.addEdge(2, 3);
// DFS from vertex 0
List<Integer> dfs0 = graph.depthFirstOrder(0);
assertEquals(4, dfs0.size());
assertEquals(0, dfs0.get(0));
// DFS from vertex 2
List<Integer> dfs2 = graph.depthFirstOrder(2);
assertEquals(4, dfs2.size());
assertEquals(2, dfs2.get(0));
// DFS from vertex 3
List<Integer> dfs3 = graph.depthFirstOrder(3);
assertEquals(4, dfs3.size());
assertEquals(3, dfs3.get(0));
}
@Test
void testBfsStartFromDifferentVertices() {
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4);
graph.addEdge(0, 1);
graph.addEdge(1, 2);
graph.addEdge(2, 3);
// BFS from vertex 0
List<Integer> bfs0 = graph.breadthFirstOrder(0);
assertEquals(4, bfs0.size());
assertEquals(0, bfs0.get(0));
// BFS from vertex 2
List<Integer> bfs2 = graph.breadthFirstOrder(2);
assertEquals(4, bfs2.size());
assertEquals(2, bfs2.get(0));
}
@Test
void testStarTopologyBfs() {
// Star graph: 0 is center connected to 1, 2, 3, 4
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(0, 3);
graph.addEdge(0, 4);
List<Integer> bfs = graph.breadthFirstOrder(0);
assertEquals(5, bfs.size());
assertEquals(0, bfs.get(0));
// All neighbors should be at distance 1
assertTrue(bfs.containsAll(Arrays.asList(1, 2, 3, 4)));
}
@Test
void testStarTopologyDfs() {
// Star graph: 0 is center connected to 1, 2, 3, 4
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(0, 3);
graph.addEdge(0, 4);
List<Integer> dfs = graph.depthFirstOrder(0);
assertEquals(5, dfs.size());
assertEquals(0, dfs.get(0));
assertTrue(dfs.containsAll(Arrays.asList(1, 2, 3, 4)));
}
@Test
void testNegativeStartVertexDfs() {
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
graph.addEdge(0, 1);
List<Integer> dfs = graph.depthFirstOrder(-1);
assertTrue(dfs.isEmpty());
}
@Test
void testNegativeStartVertexBfs() {
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
graph.addEdge(0, 1);
List<Integer> bfs = graph.breadthFirstOrder(-1);
assertTrue(bfs.isEmpty());
}
@Test
void testCompleteGraphKFour() {
// Complete graph K4: every vertex connected to every other vertex
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(4);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(0, 3);
graph.addEdge(1, 2);
graph.addEdge(1, 3);
graph.addEdge(2, 3);
assertEquals(6, graph.numberOfEdges());
List<Integer> dfs = graph.depthFirstOrder(0);
List<Integer> bfs = graph.breadthFirstOrder(0);
assertEquals(4, dfs.size());
assertEquals(4, bfs.size());
assertTrue(dfs.containsAll(Arrays.asList(0, 1, 2, 3)));
assertTrue(bfs.containsAll(Arrays.asList(0, 1, 2, 3)));
}
@Test
void testLargerGraphTraversal() {
// Create a larger graph with 10 vertices
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(10);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 3);
graph.addEdge(1, 4);
graph.addEdge(2, 5);
graph.addEdge(2, 6);
graph.addEdge(3, 7);
graph.addEdge(4, 8);
graph.addEdge(5, 9);
List<Integer> dfs = graph.depthFirstOrder(0);
List<Integer> bfs = graph.breadthFirstOrder(0);
assertEquals(10, dfs.size());
assertEquals(10, bfs.size());
assertEquals(0, dfs.get(0));
assertEquals(0, bfs.get(0));
}
@Test
void testSelfLoop() {
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(3);
graph.addEdge(0, 0); // Self loop
graph.addEdge(0, 1);
graph.addEdge(1, 2);
List<Integer> dfs = graph.depthFirstOrder(0);
List<Integer> bfs = graph.breadthFirstOrder(0);
assertEquals(3, dfs.size());
assertEquals(3, bfs.size());
}
@Test
void testLinearGraphTraversal() {
// Linear graph: 0 - 1 - 2 - 3 - 4
AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(5);
graph.addEdge(0, 1);
graph.addEdge(1, 2);
graph.addEdge(2, 3);
graph.addEdge(3, 4);
List<Integer> dfs = graph.depthFirstOrder(0);
List<Integer> bfs = graph.breadthFirstOrder(0);
assertEquals(5, dfs.size());
assertEquals(5, bfs.size());
// In a linear graph, BFS and DFS starting from 0 should be the same
assertEquals(Arrays.asList(0, 1, 2, 3, 4), dfs);
assertEquals(Arrays.asList(0, 1, 2, 3, 4), bfs);
}
}