#include "c_Graph.h" #include "c_Test.h" #include #include 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; }