package graph import ( "sort" "strings" "testing" ) func TestNewGraph(t *testing.T) { g := NewGraph[int, int]() // Check if the graph is initialized correctly if g.v != 0 { t.Errorf("NewGraph() failed: expected v = 0, got v = %d", g.v) } if g.e != 0 { t.Errorf("NewGraph() failed: expected e = 0, got e = %d", g.e) } if len(g.adjacencyList) != 0 { t.Errorf("NewGraph() failed: expected empty adjacency list, got %v", g.adjacencyList) } if len(g.edges) != 0 { t.Errorf("NewGraph() failed: expected empty edges list, got %v", g.edges) } } func TestAddEdge(t *testing.T) { g := NewGraph[int, int]() // Add edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) // Check if the edges are added correctly expectedV := 4 if g.v != expectedV { t.Errorf("AddEdge() failed: expected v = %d, got v = %d", expectedV, g.v) } expectedE := 3 if g.e != expectedE { t.Errorf("AddEdge() failed: expected e = %d, got e = %d", expectedE, g.e) } expectedAdjacencyList := map[int][]Edge[int, int]{ 1: {{1, 1, 2, 10}}, 2: {{1, 2, 1, 10}, {2, 2, 3, 20}}, 3: {{2, 3, 2, 20}, {3, 3, 4, 30}}, 4: {{3, 4, 3, 30}}, } if !compareAdjacencyLists(g.adjacencyList, expectedAdjacencyList) { t.Errorf("AddEdge() failed: expected adjacency list = %v, got %v", expectedAdjacencyList, g.adjacencyList) } expectedEdges := []Edge[int, int]{ {1, 1, 2, 10}, {2, 2, 3, 20}, {3, 3, 4, 30}, } if !compareEdges(g.edges, expectedEdges) { t.Errorf("AddEdge() failed: expected edges list = %v, got %v", expectedEdges, g.edges) } } func compareAdjacencyLists(a, b map[int][]Edge[int, int]) bool { if len(a) != len(b) { return false } for key, valueA := range a { valueB, ok := b[key] if !ok || !compareEdges(valueA, valueB) { return false } } return true } func compareEdges(a, b []Edge[int, int]) bool { if len(a) != len(b) { return false } for i := 0; i < len(a); i++ { if a[i] != b[i] { return false } } return true } func TestGetNeighbors(t *testing.T) { // Create a new graph g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(1, 3, 20) g.AddEdge(2, 3, 30) // Test GetNeighbors for vertex 1 neighbors := g.GetNeighbors(1) expectedNeighbors := []Edge[int, int]{{ID: 1, src: 1, dest: 2, weight: 10}, {ID: 2, src: 1, dest: 3, weight: 20}} if !equalEdges(neighbors, expectedNeighbors) { t.Errorf("GetNeighbors() failed for vertex 1: expected %v, got %v", expectedNeighbors, neighbors) } // Test GetNeighbors for vertex 2 neighbors = g.GetNeighbors(2) expectedNeighbors = []Edge[int, int]{{ID: 1, src: 2, dest: 1, weight: 10}, {ID: 3, src: 2, dest: 3, weight: 30}} if !equalEdges(neighbors, expectedNeighbors) { t.Errorf("GetNeighbors() failed for vertex 2: expected %v, got %v", expectedNeighbors, neighbors) } // Test GetNeighbors for vertex 3 neighbors = g.GetNeighbors(3) expectedNeighbors = []Edge[int, int]{{ID: 2, src: 3, dest: 1, weight: 20}, {ID: 3, src: 3, dest: 2, weight: 30}} if !equalEdges(neighbors, expectedNeighbors) { t.Errorf("GetNeighbors() failed for vertex 3: expected %v, got %v", expectedNeighbors, neighbors) } } // Helper function to check if two slices of edges are equal func equalEdges(edges1, edges2 []Edge[int, int]) bool { if len(edges1) != len(edges2) { return false } for i := 0; i < len(edges1); i++ { if edges1[i] != edges2[i] { return false } } return true } func TestHasNeighbor(t *testing.T) { g := NewGraph[int, int]() // Add edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(1, 3, 20) g.AddEdge(2, 3, 30) // Test HasNeighbor for existing neighbors if !g.HasNeighbor(1, 2) { t.Errorf("HasNeighbor() failed: expected true, got false") } if !g.HasNeighbor(1, 3) { t.Errorf("HasNeighbor() failed: expected true, got false") } if !g.HasNeighbor(2, 3) { t.Errorf("HasNeighbor() failed: expected true, got false") } if !g.HasNeighbor(3, 1) { t.Errorf("HasNeighbor() failed: expected true, got false") } if !g.HasNeighbor(2, 1) { t.Errorf("HasNeighbor() failed: expected true, got false") } // Test HasNeighbor for non-existing neighbors if g.HasNeighbor(1, 4) { t.Errorf("HasNeighbor() failed: expected false, got true") } } func TestGetEdge(t *testing.T) { g := NewGraph[int, int]() g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) // Test existing edge expectedEdge := Edge[int, int]{ID: 1, src: 1, dest: 2, weight: 10} edge := g.GetEdge(1, 2) if edge != expectedEdge { t.Errorf("GetEdge() failed for existing edge: expected %v, got %v", expectedEdge, edge) } // Test non-existing edge edge = g.GetEdge(1, 3) if edge != (Edge[int, int]{}) { t.Errorf("GetEdge() failed for non-existing edge: expected empty edge, got %v", edge) } } func TestString(t *testing.T) { g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(1, 3, 20) g.AddEdge(2, 3, 30) result := g.String() if !strings.Contains(result, "1: (1, 1, 2, 10) (2, 1, 3, 20)\n") || !strings.Contains(result, "2: (1, 2, 1, 10) (3, 2, 3, 30)\n") || !strings.Contains(result, "3: (2, 3, 1, 20) (3, 3, 2, 30)\n") { t.Errorf("String() failed and got %q", result) } } func TestCountComponents(t *testing.T) { g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(4, 5, 30) expectedCount := 2 actualCount := g.CountComponents() if actualCount != expectedCount { t.Errorf("CountComponents() failed: expected count = %d, got count = %d", expectedCount, actualCount) } // Add another component to the graph g.AddEdge(6, 7, 40) g.AddEdge(7, 8, 50) expectedCount = 3 actualCount = g.CountComponents() if actualCount != expectedCount { t.Errorf("CountComponents() failed: expected count = %d, got count = %d", expectedCount, actualCount) } } func TestIsConnected(t *testing.T) { g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) // Test IsConnected for a connected graph if !g.IsConnected() { t.Errorf("IsConnected() failed: expected true, got false") } // Test IsConnected for a disconnected graph g.AddVertex(5) if g.IsConnected() { t.Errorf("IsConnected() failed: expected false, got true") } } func TestIsCyclic(t *testing.T) { g := NewGraph[int, int]() // Add edges to create a cyclic graph g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 1, 30) // Check if the graph is cyclic if !g.IsCyclic() { t.Errorf("IsCyclic() failed: expected true, got false") } // Add edges to create an acyclic graph g = NewGraph[int, int]() g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) // Check if the graph is acyclic if g.IsCyclic() { t.Errorf("IsCyclic() failed: expected false, got true") } } func TestIsCyclicUtil(t *testing.T) { g := NewGraph[int, int]() g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 1, 30) visited := make(map[int]bool) recStack := make(map[int]bool) edgeIDs := make(map[int]bool) // Test for cyclic graph if !g.isCyclicUtil(1, visited, recStack, edgeIDs) { t.Errorf("isCyclicUtil() failed: expected true, got false") } g = NewGraph[int, int]() g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) visited = make(map[int]bool) recStack = make(map[int]bool) edgeIDs = make(map[int]bool) // Test for acyclic graph if g.isCyclicUtil(1, visited, recStack, edgeIDs) { t.Errorf("isCyclicUtil() failed: expected false, got true") } } func TestIsTree(t *testing.T) { // Create a new graph g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) // Test IsTree for a connected acyclic graph if !g.IsTree() { t.Errorf("IsTree() failed for a connected acyclic graph") } // Add an edge to create a cycle g.AddEdge(4, 1, 40) // Test IsTree for a graph with a cycle if g.IsTree() { t.Errorf("IsTree() failed for a graph with a cycle") } // Remove the edge to make the graph acyclic again g.RemoveEdge(4, 1) // Remove a vertex to make the graph disconnected g.RemoveVertex(3) // Test IsTree for a disconnected graph if g.IsTree() { t.Errorf("IsTree() failed for a disconnected graph") } } func TestIsBipartite(t *testing.T) { g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(1, 3, 20) g.AddEdge(3, 4, 40) // Test for a bipartite graph if !g.IsBipartite() { t.Error("IsBipartite() failed for a bipartite graph") } // Add an edge to create a cycle g.AddEdge(4, 1, 50) // Test for a non-bipartite graph with a cycle if g.IsBipartite() { t.Error("IsBipartite() failed for a non-bipartite graph with a cycle") } // Remove the edge to break the cycle g.RemoveEdge(4, 1) // Test for a non-bipartite graph without a cycle if !g.IsBipartite() { t.Error("IsBipartite() failed for a non-bipartite graph without a cycle") } } func TestIsBipartiteUtil(t *testing.T) { g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) visited := make(map[int]bool) colors := make(map[int]bool) edgeIDs := map[int]bool{} // Test isBipartiteUtil for a bipartite graph result := g.isBipartiteUtil(1, visited, colors, edgeIDs) expectedResult := true if result != expectedResult { t.Errorf("isBipartiteUtil() failed for bipartite graph: expected %v, got %v", expectedResult, result) } visited = make(map[int]bool) colors = make(map[int]bool) edgeIDs = map[int]bool{} // Test isBipartiteUtil for a non-bipartite graph g.AddEdge(4, 2, 40) result = g.isBipartiteUtil(1, visited, colors, edgeIDs) expectedResult = false if result != expectedResult { t.Errorf("isBipartiteUtil() failed for non-bipartite graph: expected %v, got %v", expectedResult, result) } } func TestAddVertex(t *testing.T) { g := NewGraph[int, int]() // Add a vertex to the graph g.AddVertex(1) // Check if the vertex is added correctly expectedAdjacencyList := map[int][]Edge[int, int]{ 1: {}, } if !compareAdjacencyLists(g.adjacencyList, expectedAdjacencyList) { t.Errorf("AddVertex() failed: expected adjacency list = %v, got %v", expectedAdjacencyList, g.adjacencyList) } } func TestGetVertices(t *testing.T) { g := NewGraph[int, int]() // Add vertices to the graph g.AddVertex(1) g.AddVertex(2) g.AddVertex(3) // Get the vertices from the graph vertices := g.GetVertices() // Check if the vertices are returned correctly expectedVertices := []int{1, 2, 3} if !equalSlices(vertices, expectedVertices) { t.Errorf("GetVertices() failed: expected %v, got %v", expectedVertices, vertices) } } // Helper function to check if two slices are equal func equalSlices(a, b []int) bool { sort.Ints(a) sort.Ints(b) if len(a) != len(b) { return false } for i := 0; i < len(a); i++ { if a[i] != b[i] { return false } } return true } func TestRemoveEdge(t *testing.T) { g := NewGraph[int, int]() g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) // Test removing an existing edge g.RemoveEdge(1, 2) if edges := g.GetEdges(); len(edges) != 2 { t.Errorf("RemoveEdge() failed: expected 2 edges, got %d", len(edges)) } if neighbors := g.GetNeighbors(1); len(neighbors) != 0 { t.Errorf("RemoveEdge() failed: expected 0 neighbors for vertex 1, got %d", len(neighbors)) } if neighbors := g.GetNeighbors(2); len(neighbors) != 1 { t.Errorf("RemoveEdge() failed: expected 1 neighbor for vertex 2, got %d", len(neighbors)) } // Test removing a non-existing edge g.RemoveEdge(1, 3) if edges := g.GetEdges(); len(edges) != 2 { t.Errorf("RemoveEdge() failed: expected 2 edges, got %d", len(edges)) } if neighbors := g.GetNeighbors(1); len(neighbors) != 0 { t.Errorf("RemoveEdge() failed: expected 0 neighbors for vertex 1, got %d", len(neighbors)) } if neighbors := g.GetNeighbors(3); len(neighbors) != 2 { t.Errorf("RemoveEdge() failed: expected 1 neighbor for vertex 3, got %d", len(neighbors)) } } func TestRemoveVertex(t *testing.T) { g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(1, 3, 20) g.AddEdge(2, 3, 30) g.AddEdge(3, 4, 40) // Remove vertex 2 g.RemoveVertex(2) // Check if the vertex is removed correctly expectedAdjacencyList := map[int][]Edge[int, int]{ 1: {{2, 1, 3, 20}}, 3: {{2, 3, 1, 20}, {4, 3, 4, 40}}, 4: {{4, 4, 3, 40}}, } if !compareAdjacencyLists(g.adjacencyList, expectedAdjacencyList) { t.Errorf("RemoveVertex() failed: expected adjacency list = %v, got %v", expectedAdjacencyList, g.adjacencyList) } expectedEdges := []Edge[int, int]{ {2, 1, 3, 20}, {4, 3, 4, 40}, } if !compareEdges(g.edges, expectedEdges) { t.Errorf("RemoveVertex() failed: expected edges list = %v, got %v", expectedEdges, g.edges) } expectedV := 3 if g.v != expectedV { t.Errorf("RemoveVertex() failed: expected v = %d, got v = %d", expectedV, g.v) } expectedE := 2 if g.e != expectedE { t.Errorf("RemoveVertex() failed: expected e = %d, got e = %d", expectedE, g.e) } } func TestGetEdges(t *testing.T) { g := NewGraph[int, int]() g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) // Test GetEdges expectedEdges := []Edge[int, int]{ {ID: 1, src: 1, dest: 2, weight: 10}, {ID: 2, src: 2, dest: 3, weight: 20}, {ID: 3, src: 3, dest: 4, weight: 30}, } edges := g.GetEdges() if !compareEdges(edges, expectedEdges) { t.Errorf("GetEdges() failed: expected edges = %v, got edges = %v", expectedEdges, edges) } } func TestRemoveEdgeWithID(t *testing.T) { g := NewGraph[int, int]() g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) // Test removing an existing edge g.RemoveEdgeWithID(1) // Check if the edge is removed from the list of edges expectedEdges := []Edge[int, int]{ {ID: 2, src: 2, dest: 3, weight: 20}, {ID: 3, src: 3, dest: 4, weight: 30}, } if !compareEdges(g.edges, expectedEdges) { t.Errorf("RemoveEdgeWithID() failed: expected edges list = %v, got %v", expectedEdges, g.edges) } // Check if the edge is removed from the adjacency list expectedAdjacencyList := map[int][]Edge[int, int]{ 1: {}, 2: {{2, 2, 3, 20}}, 3: {{2, 3, 2, 20}, {3, 3, 4, 30}}, 4: {{3, 4, 3, 30}}, } if !compareAdjacencyLists(g.adjacencyList, expectedAdjacencyList) { t.Errorf("RemoveEdgeWithID() failed: expected adjacency list = %v, got %v", expectedAdjacencyList, g.adjacencyList) } // Check if the edge count is updated expectedE := 2 if g.e != expectedE { t.Errorf("RemoveEdgeWithID() failed: expected e = %d, got e = %d", expectedE, g.e) } // Test removing a non-existing edge g.RemoveEdgeWithID(5) // Check if the graph remains unchanged if !compareEdges(g.edges, expectedEdges) { t.Errorf("RemoveEdgeWithID() failed: expected edges list = %v, got %v", expectedEdges, g.edges) } if !compareAdjacencyLists(g.adjacencyList, expectedAdjacencyList) { t.Errorf("RemoveEdgeWithID() failed: expected adjacency list = %v, got %v", expectedAdjacencyList, g.adjacencyList) } if g.e != expectedE { t.Errorf("RemoveEdgeWithID() failed: expected e = %d, got e = %d", expectedE, g.e) } } func TestKargerMinCutUF(t *testing.T) { // Create a new graph g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(1, 3, 20) g.AddEdge(2, 3, 30) g.AddEdge(3, 4, 40) g.AddEdge(4, 5, 50) g.AddEdge(4, 6, 60) g.AddEdge(5, 6, 70) // Run Karger's algorithm to find the minimum cut cutEdges, resultSubsets := g.kargerMinCutUF(100) // Check if the number of cut edges is correct expectedCutEdges := 1 if cutEdges != expectedCutEdges { t.Errorf("kargerMinCutUF() failed: expected cut edges = %d, got cut edges = %d", expectedCutEdges, cutEdges) } // Check if the result subsets are correct expectedResultSubsets := [][]int{{1, 2, 3}, {4, 5, 6}} if !equalSubsets(resultSubsets, expectedResultSubsets) { t.Errorf("kargerMinCutUF() failed: expected result subsets = %v, got result subsets = %v", expectedResultSubsets, resultSubsets) } } // Helper function to check if two subsets are equal func equalSubsets(a, b [][]int) bool { if len(a) != len(b) { return false } for i := 0; i < len(a); i++ { if !equalSlices(a[i], b[i]) { return false } } return true } func TestBFS(t *testing.T) { g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(1, 3, 20) g.AddEdge(2, 3, 30) g.AddEdge(2, 4, 40) g.AddEdge(3, 4, 50) // Define the isGoal function isGoal := func(vertex int) bool { return vertex == 4 } // Perform BFS starting from vertex 1 result := g.BFS(1, isGoal) // Check if the result is correct expectedResult := []int{1, 2, 3, 4} if !equalSlices(result, expectedResult) { t.Errorf("BFS() failed: expected %v, got %v", expectedResult, result) } // Perform BFS starting from vertex 2 result = g.BFS(2, isGoal) // Check if the result is correct expectedResult = []int{2, 1, 3, 4} if !equalSlices(result, expectedResult) { t.Errorf("BFS() failed: expected %v, got %v", expectedResult, result) } // Perform BFS starting from vertex 3 result = g.BFS(3, isGoal) // Check if the result is correct expectedResult = []int{3, 1, 2, 4} if !equalSlices(result, expectedResult) { t.Errorf("BFS() failed: expected %v, got %v", expectedResult, result) } // Perform BFS starting from vertex 4 result = g.BFS(4, isGoal) // Check if the result is correct expectedResult = []int{4} if !equalSlices(result, expectedResult) { t.Errorf("BFS() failed: expected %v, got %v", expectedResult, result) } } func TestDFS(t *testing.T) { g := NewGraph[int, int]() g.AddEdge(1, 2, 10) g.AddEdge(2, 3, 20) g.AddEdge(3, 4, 30) g.AddEdge(4, 5, 40) g.AddEdge(5, 6, 50) // Test DFS with a goal function that returns true for vertex 6 isGoal := func(vertex int) bool { return vertex == 6 } result := g.DFS(1, isGoal) expectedResult := []int{1, 2, 3, 4, 5, 6} if !equalSlices(result, expectedResult) { t.Errorf("DFS() failed with goal function: expected %v, got %v", expectedResult, result) } // Test DFS with a goal function that returns true for vertex 3 isGoal = func(vertex int) bool { return vertex == 3 } result = g.DFS(1, isGoal) expectedResult = []int{1, 2, 3} if !equalSlices(result, expectedResult) { t.Errorf("DFS() failed with goal function: expected %v, got %v", expectedResult, result) } // Test DFS with a goal function that returns true for vertex 7 (non-existent vertex) isGoal = func(vertex int) bool { return vertex == 7 } result = g.DFS(1, isGoal) expectedResult = []int{} if !equalSlices(result, expectedResult) { t.Errorf("DFS() failed with goal function: expected %v, got %v", expectedResult, result) } } func TestDijkstra(t *testing.T) { g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(1, 3, 20) g.AddEdge(2, 3, 30) g.AddEdge(2, 4, 40) g.AddEdge(3, 4, 50) // Test Dijkstra algorithm start := 1 goal := 4 expectedPath := []int{1, 2, 4} path := g.Dijkstra(start, goal) if !equalSlices(path, expectedPath) { t.Errorf("Dijkstra() failed: expected path = %v, got path = %v", expectedPath, path) } } func TestAStar(t *testing.T) { g := NewGraph[int, int]() // Add vertices and edges to the graph g.AddEdge(1, 2, 10) g.AddEdge(1, 3, 20) g.AddEdge(2, 3, 30) g.AddEdge(2, 4, 40) g.AddEdge(3, 4, 50) g.AddEdge(3, 5, 60) g.AddEdge(4, 5, 70) // Define the heuristic function heuristic := func(vertex int) int { return 0 // equivalent of Disjkstra's algorithm } // Test AStar for a valid path start := 1 goal := 5 expectedPath := []int{1, 3, 5} path := g.AStar(start, goal, heuristic) if !equalSlices(path, expectedPath) { t.Errorf("AStar() failed for valid path: expected %v, got %v", expectedPath, path) } // Test AStar for an invalid path start = 1 goal = 6 expectedPath = []int{} path = g.AStar(start, goal, heuristic) if !equalSlices(path, expectedPath) { t.Errorf("AStar() failed for invalid path: expected %v, got %v", expectedPath, path) } }