This commit is contained in:
2026-09-07 18:48:16 +08:00
parent 1564716731
commit c945aa211f
138 changed files with 10337 additions and 150 deletions
+87
View File
@@ -0,0 +1,87 @@
#include "c_Test.h"
#include "c_CPM.h"
/* External declaration of helper from c_CPM.c */
static c_err_t c_CPM_CreateWorkingGraph(c_CPM_t* self, const double* task_durations, c_EdgeWeightedDigraph_t* out_graph) {
c_err_t err = c_EdgeWeightedDigraph_Init(out_graph, self->V, &self->allocator);
if (err != C_SUCCESS) return err;
for (c_size_t i = 0; i < self->num_tasks; ++i) {
/* Connect Start node i to Finish node (i + num_tasks) using duration weight */
err = c_EdgeWeightedDigraph_AddEdge(out_graph, i, i + self->num_tasks, task_durations[i]);
if (err != C_SUCCESS) goto fallback;
/* Hook virtual network source up to task start nodes */
err = c_EdgeWeightedDigraph_AddEdge(out_graph, self->source_node, i, 0.0);
if (err != C_SUCCESS) goto fallback;
/* Hook task finish nodes down into virtual destination sink node */
err = c_EdgeWeightedDigraph_AddEdge(out_graph, i + self->num_tasks, self->sink_node, 0.0);
if (err != C_SUCCESS) goto fallback;
}
return C_SUCCESS;
fallback:
c_EdgeWeightedDigraph_Destroy(out_graph);
return err;
}
TEST_CASE(test_critical_path_method_scheduling) {
/* Let's model a 3-task project layout:
* Task 0: Duration 5.0 days
* Task 1: Duration 10.0 days
* Task 2: Duration 3.0 days
* Constraint: Task 0 and Task 1 can start immediately in parallel.
* Constraint: Task 2 depends on Task 0 (Task 0 must finish before Task 2 starts).
*/
double durations[3] = {5.0, 10.0, 3.0};
c_CPM_t cpm;
c_err_t err = c_CPM_Init(&cpm, 3, durations, NULL);
ASSERT_INT_EQ(C_SUCCESS, err);
c_EdgeWeightedDigraph_t working_graph;
err = c_CPM_CreateWorkingGraph(&cpm, durations, &working_graph);
ASSERT_INT_EQ(C_SUCCESS, err);
/* Establish dependency constraint: Task 0 must finish before Task 2 begins */
err = c_CPM_AddDependency(&cpm, &working_graph, 0, 2);
ASSERT_INT_EQ(C_SUCCESS, err);
/* Run calculations */
err = c_CPM_Calculate(&cpm, &working_graph);
ASSERT_INT_EQ(C_SUCCESS, err);
/*
* Let's trace timelines:
* Path A (via Task 0 & 2): Duration = 5.0 (Task 0) + 3.0 (Task 2) = 8.0 days.
* Path B (via Task 1): Duration = 10.0 days.
* The total project duration is governed by the longest path (critical bottleneck) = 10.0 days.
*/
ASSERT_DOUBLE_EQ_MSG(10.0, c_CPM_GetProjectDuration(&cpm), "Project duration calculation failed");
/* Verify Early Start milestones */
ASSERT_DOUBLE_EQ_MSG(0.0, c_CPM_GetEarlyStart(&cpm, 0), "Task 0 should start at day 0");
ASSERT_DOUBLE_EQ_MSG(0.0, c_CPM_GetEarlyStart(&cpm, 1), "Task 1 should start at day 0");
ASSERT_DOUBLE_EQ_MSG(5.0, c_CPM_GetEarlyStart(&cpm, 2), "Task 2 should start at day 5 after Task 0 finishes");
/* Reconstruct critical path edges sequence tokens */
c_VertexIdList_t critical_path;
c_VertexIdList_Init(&critical_path, 0, 0);
err = c_CPM_GetCriticalPath(&cpm, &critical_path);
ASSERT_INT_EQ(C_SUCCESS, err);
ASSERT_TRUE(c_VertexIdList_GetSize(&critical_path) > 0);
c_VertexIdList_Destroy(&critical_path);
c_CPM_Destroy(&cpm);
c_EdgeWeightedDigraph_Destroy(&working_graph);
}
int main(void) {
TEST_START(CPM_ProjectManagement_Suite);
RUN_TEST(test_critical_path_method_scheduling);
TEST_REPORT();
RETURN_TEST_STATUS;
}