Files

206 lines
6.9 KiB
C
Raw Permalink Normal View History

2026-09-05 13:36:43 +08:00
#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;
}