You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

725 lines
18 KiB
Go

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(10000)
// 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)
}
}