#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; }