206 lines
6.9 KiB
C
206 lines
6.9 KiB
C
#include "c_Graph.h"
|
|
#include "c_Test.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
|
|
TEST_CASE(test_array_graph_memcpy_deep_copy) {
|
|
c_Graph_t original;
|
|
c_Graph_Init(&original, 3, 0);
|
|
|
|
// Build connections: 0 -> 1, 0 -> 2, 1 -> 2
|
|
c_Graph_AddEdge(&original, 0, 1);
|
|
c_Graph_AddEdge(&original, 0, 2);
|
|
c_Graph_AddEdge(&original, 1, 2);
|
|
|
|
// Perform the high-efficiency deep copy
|
|
c_Graph_t cloned;
|
|
c_err_t err = c_Graph_Copy(&cloned, &original, 0);
|
|
|
|
// Assert scalar metrics validation matches perfectly
|
|
ASSERT_INT_EQ(C_SUCCESS, err);
|
|
ASSERT_LL_EQ(original.V, cloned.V);
|
|
ASSERT_LL_EQ(original.E, cloned.E);
|
|
|
|
// Assert that structural internal memory segments match completely
|
|
for (c_size_t i = 0; i < original.V; i++) {
|
|
ASSERT_LL_EQ(original.adj_list[i].size, cloned.adj_list[i].size);
|
|
|
|
c_size_t bytes_to_compare = original.adj_list[i].size * sizeof(c_uint_t);
|
|
if (bytes_to_compare > 0) {
|
|
// Memory addresses must be completely distinct (Deep Copy checking rule)
|
|
ASSERT_TRUE(original.adj_list[i].array != cloned.adj_list[i].array);
|
|
// Element contents must be identical bitwise
|
|
int mem_cmp_res = memcmp(original.adj_list[i].array, cloned.adj_list[i].array, bytes_to_compare);
|
|
ASSERT_INT_EQ(0, mem_cmp_res);
|
|
}
|
|
}
|
|
|
|
// Clean up graph allocation structures
|
|
c_Graph_Destroy(&original);
|
|
c_Graph_Destroy(&cloned);
|
|
}
|
|
|
|
TEST_CASE(test_graph_init_and_destroy) {
|
|
c_Graph_t graph;
|
|
c_err_t err = c_Graph_Init(&graph, 5, 0);
|
|
|
|
ASSERT_INT_EQ_MSG(C_SUCCESS, err, "Graph initialization should succeed");
|
|
ASSERT_LL_EQ(5, graph.V);
|
|
ASSERT_LL_EQ(0, graph.E);
|
|
ASSERT_PTR_NOT_NULL(graph.adj_list);
|
|
|
|
// Verify all individual adjacency rows are empty and correctly initialized
|
|
for (c_size_t i = 0; i < 5; i++) {
|
|
ASSERT_TRUE(c_AdjList_IsEmpty(&graph.adj_list[i]));
|
|
ASSERT_LL_EQ(0, graph.adj_list[i].size);
|
|
}
|
|
|
|
c_Graph_Destroy(&graph);
|
|
ASSERT_TRUE(graph.adj_list == NULL);
|
|
ASSERT_LL_EQ(0, graph.V);
|
|
ASSERT_LL_EQ(0, graph.E);
|
|
}
|
|
|
|
// Test Case 2: Standard Undirected Edge Insertion & Degree Tracking
|
|
TEST_CASE(test_graph_add_edge_and_degree) {
|
|
c_Graph_t graph;
|
|
c_Graph_Init(&graph, 4, 0);
|
|
|
|
// Insert an edge between 0 and 1
|
|
c_err_t err1 = c_Graph_AddEdge(&graph, 0, 1);
|
|
ASSERT_INT_EQ(C_SUCCESS, err1);
|
|
ASSERT_LL_EQ(1, graph.E);
|
|
|
|
// Verify symmetric property (Undirected graph invariant)
|
|
ASSERT_LL_EQ(1, c_Graph_Degree(&graph, 0));
|
|
ASSERT_LL_EQ(1, c_Graph_Degree(&graph, 1));
|
|
|
|
// Add more edges to create a small triangle with an outer arm: 0-1, 1-2, 2-0, 2-3
|
|
c_Graph_AddEdge(&graph, 1, 2);
|
|
c_Graph_AddEdge(&graph, 2, 0);
|
|
c_Graph_AddEdge(&graph, 2, 3);
|
|
|
|
ASSERT_LL_EQ(4, graph.E);
|
|
|
|
// Verify individual vertex degrees
|
|
ASSERT_LL_EQ(2, c_Graph_Degree(&graph, 0)); // neighbors: 1, 2
|
|
ASSERT_LL_EQ(2, c_Graph_Degree(&graph, 1)); // neighbors: 0, 2
|
|
ASSERT_LL_EQ(3, c_Graph_Degree(&graph, 2)); // neighbors: 1, 0, 3
|
|
ASSERT_LL_EQ(1, c_Graph_Degree(&graph, 3)); // neighbor: 2
|
|
|
|
// Check specific neighbor values within the array-backed list
|
|
c_AdjList_t* list_v2 = c_Graph_GetAdjList(&graph, 2);
|
|
ASSERT_PTR_NOT_NULL(list_v2);
|
|
|
|
c_uint_t neighbor_val;
|
|
c_AdjList_Get(list_v2, 0, &neighbor_val); ASSERT_LL_EQ(1, neighbor_val);
|
|
c_AdjList_Get(list_v2, 1, &neighbor_val); ASSERT_LL_EQ(0, neighbor_val);
|
|
c_AdjList_Get(list_v2, 2, &neighbor_val); ASSERT_LL_EQ(3, neighbor_val);
|
|
|
|
c_Graph_Destroy(&graph);
|
|
}
|
|
|
|
// Test Case 3: Edge Case Bounds & Self-Loops Validation
|
|
TEST_CASE(test_graph_edge_cases) {
|
|
c_Graph_t graph;
|
|
c_Graph_Init(&graph, 3, 0);
|
|
|
|
// Out of bounds vertex parameter checks
|
|
c_err_t err_bad1 = c_Graph_AddEdge(&graph, 0, 5);
|
|
c_err_t err_bad2 = c_Graph_AddEdge(&graph, 3, 1);
|
|
ASSERT_INT_EQ_MSG(C_ERR_PARAM, err_bad1, "Out-of-bounds destination should return parameter error");
|
|
ASSERT_INT_EQ_MSG(C_ERR_PARAM, err_bad2, "Out-of-bounds source should return parameter error");
|
|
|
|
// Self-loop validation (0 <-> 0)
|
|
c_err_t err_loop = c_Graph_AddEdge(&graph, 0, 0);
|
|
ASSERT_INT_EQ(C_SUCCESS, err_loop);
|
|
ASSERT_LL_EQ(1, graph.E);
|
|
ASSERT_LL_EQ(1, c_Graph_Degree(&graph, 0)); // Standard self-loop updates list once
|
|
|
|
c_Graph_Destroy(&graph);
|
|
}
|
|
|
|
TEST_CASE(test_graph_remove_edge) {
|
|
c_Graph_t graph;
|
|
c_Graph_Init(&graph, 4, 0);
|
|
|
|
// Build paths: 0-1, 1-2, 2-2 (Self loop)
|
|
c_Graph_AddEdge(&graph, 0, 1);
|
|
c_Graph_AddEdge(&graph, 1, 2);
|
|
c_Graph_AddEdge(&graph, 2, 2);
|
|
ASSERT_LL_EQ(3, graph.E);
|
|
|
|
// 1. Test standard edge removal (1 <-> 2)
|
|
c_err_t err = c_Graph_RemoveEdge(&graph, 1, 2);
|
|
ASSERT_INT_EQ(C_SUCCESS, err);
|
|
ASSERT_LL_EQ(2, graph.E);
|
|
ASSERT_LL_EQ(1, c_Graph_Degree(&graph, 1)); // should only have 0 left
|
|
ASSERT_LL_EQ(1, c_Graph_Degree(&graph, 2)); // should only have self-loop left
|
|
|
|
// 2. Test self-loop removal (2 <-> 2)
|
|
err = c_Graph_RemoveEdge(&graph, 2, 2);
|
|
ASSERT_INT_EQ(C_SUCCESS, err);
|
|
ASSERT_LL_EQ(1, graph.E);
|
|
ASSERT_LL_EQ(0, c_Graph_Degree(&graph, 2)); // now isolated
|
|
|
|
// 3. Test removing a non-existent edge
|
|
err = c_Graph_RemoveEdge(&graph, 0, 3);
|
|
ASSERT_INT_EQ_MSG(C_ERR_FAIL, err, "Removing non-existent edge must return failure status");
|
|
|
|
// 4. Test boundary parameter filtering
|
|
err = c_Graph_RemoveEdge(&graph, 0, 99);
|
|
ASSERT_INT_EQ_MSG(C_ERR_PARAM, err, "Out-of-bounds parameters must return param error");
|
|
|
|
c_Graph_Destroy(&graph);
|
|
}
|
|
|
|
TEST_CASE(test_graph_has_edge) {
|
|
c_Graph_t graph;
|
|
c_Graph_Init(&graph, 4, 0);
|
|
|
|
// Form edges: 0-1, 1-2, 3-3 (Self-loop)
|
|
c_Graph_AddEdge(&graph, 0, 1);
|
|
c_Graph_AddEdge(&graph, 1, 2);
|
|
c_Graph_AddEdge(&graph, 3, 3);
|
|
|
|
// 1. Verify standard existing edges (Check symmetry explicitly)
|
|
ASSERT_TRUE(c_Graph_HasEdge(&graph, 0, 1));
|
|
ASSERT_TRUE(c_Graph_HasEdge(&graph, 1, 0));
|
|
ASSERT_TRUE(c_Graph_HasEdge(&graph, 1, 2));
|
|
ASSERT_TRUE(c_Graph_HasEdge(&graph, 2, 1));
|
|
|
|
// 2. Verify self-loop edge existence
|
|
ASSERT_TRUE(c_Graph_HasEdge(&graph, 3, 3));
|
|
|
|
// 3. Verify non-existent edges
|
|
ASSERT_FALSE(c_Graph_HasEdge(&graph, 0, 2));
|
|
ASSERT_FALSE(g_test_registry.failed_count > 0); // Framework status checkpoint
|
|
ASSERT_FALSE(c_Graph_HasEdge(&graph, 0, 3));
|
|
|
|
// 4. Verify boundary input error filters return C_FALSE safely
|
|
ASSERT_FALSE(c_Graph_HasEdge(&graph, 0, 99));
|
|
ASSERT_FALSE(c_Graph_HasEdge(&graph, 99, 1));
|
|
|
|
c_Graph_Destroy(&graph);
|
|
}
|
|
|
|
|
|
int main(int argc, char** argv){
|
|
TEST_START(Unit Tests);
|
|
|
|
// 运行普通无环境要求的用例
|
|
RUN_TEST(test_graph_init_and_destroy);
|
|
RUN_TEST(test_graph_add_edge_and_degree);
|
|
RUN_TEST(test_graph_edge_cases);
|
|
RUN_TEST(test_array_graph_memcpy_deep_copy);
|
|
RUN_TEST(test_graph_remove_edge);
|
|
RUN_TEST(test_graph_has_edge);
|
|
|
|
// 打印最终统计报告
|
|
TEST_REPORT();
|
|
|
|
RETURN_TEST_STATUS;
|
|
}
|