#include #include #include "app.hpp" #include #include #include using namespace testing; // ============================================================================ // 测试夹具:CmsEngineTest // ============================================================================ class CmsEngineTest : public ::testing::Test { protected: void SetUp() override { // 初始化引擎 engine = new CmsEngine(); // 准备测试事件 EventRecord event1; event1.id = "EVT-001"; event1.status = EventStatus::Pending; event1.priority = 100; EventRecord event2; event2.id = "EVT-002"; event2.status = EventStatus::Pending; event2.priority = 200; EventRecord event3; event3.id = "EVT-003"; event3.status = EventStatus::Generated; // 非 Pending 状态 event3.priority = 150; // 注入测试事件 engine->ingestEvent(event1); engine->ingestEvent(event2); engine->ingestEvent(event3); } void TearDown() override { delete engine; } CmsEngine* engine; }; // ============================================================================ // 测试用例:processPendingEvents // ============================================================================ /** * @brief 测试正常处理待处理事件 * * 验证 processPendingEvents 能正确处理所有 Pending 状态的事件, * 并返回正确的处理数量。 */ TEST_F(CmsEngineTest, testProcessPendingEventsNormal) { // 执行 size_t processedCount = engine->processPendingEvents(); // 验证:应该有 2 个 Pending 事件被处理 EXPECT_EQ(processedCount, 2); // 验证事件状态已更新 const EventRecord* evt1 = engine->findEventById("EVT-001"); ASSERT_NE(evt1, nullptr); EXPECT_EQ(evt1->status, EventStatus::Generated); const EventRecord* evt2 = engine->findEventById("EVT-002"); ASSERT_NE(evt2, nullptr); EXPECT_EQ(evt2->status, EventStatus::Generated); // 验证非 Pending 事件状态不变 const EventRecord* evt3 = engine->findEventById("EVT-003"); ASSERT_NE(evt3, nullptr); EXPECT_EQ(evt3->status, EventStatus::Generated); // 原本就是 Generated // 验证生成了对应的 TaskPlan const std::vector& plans = engine->getAllPlans(); EXPECT_EQ(plans.size(), 2); // 验证第一个 Plan 的关联事件 ID EXPECT_EQ(plans[0].relatedEventId, "EVT-001"); EXPECT_EQ(plans[0].type, PlanType::Centralized); EXPECT_EQ(plans[0].status, PlanStatus::Drafting); EXPECT_NEAR(plans[0].resourceQuota, 0.5, 0.001); // 验证第二个 Plan 的关联事件 ID EXPECT_EQ(plans[1].relatedEventId, "EVT-002"); } /** * @brief 测试无待处理事件的情况 * * 验证当没有 Pending 状态的事件时,processPendingEvents 返回 0。 */ TEST_F(CmsEngineTest, testProcessPendingEventsNoPending) { // 先处理所有 Pending 事件 engine->processPendingEvents(); // 再次调用,此时没有 Pending 事件 size_t processedCount = engine->processPendingEvents(); // 验证:应该处理 0 个事件 EXPECT_EQ(processedCount, 0); // 验证 Plan 数量没有增加 const std::vector& plans = engine->getAllPlans(); EXPECT_EQ(plans.size(), 2); // 第一次处理时生成的 2 个 } /** * @brief 测试空事件库的情况 * * 验证当事件库为空时,processPendingEvents 返回 0。 */ TEST_F(CmsEngineTest, testProcessPendingEventsEmptyEvents) { // 创建一个新的空引擎 CmsEngine emptyEngine; // 执行 size_t processedCount = emptyEngine.processPendingEvents(); // 验证:应该处理 0 个事件 EXPECT_EQ(processedCount, 0); // 验证 Plan 列表为空 const std::vector& plans = emptyEngine.getAllPlans(); EXPECT_TRUE(plans.empty()); } /** * @brief 测试多次调用 processPendingEvents * * 验证多次调用不会重复处理已处理的事件。 */ TEST_F(CmsEngineTest, testProcessPendingEventsMultipleCalls) { // 第一次调用 size_t firstCount = engine->processPendingEvents(); EXPECT_EQ(firstCount, 2); // 第二次调用 size_t secondCount = engine->processPendingEvents(); EXPECT_EQ(secondCount, 0); // 没有新的 Pending 事件 // 第三次调用 size_t thirdCount = engine->processPendingEvents(); EXPECT_EQ(thirdCount, 0); // 验证 Plan 数量始终为 2 const std::vector& plans = engine->getAllPlans(); EXPECT_EQ(plans.size(), 2); } // ============================================================================ // 测试用例:findEventById // ============================================================================ /** * @brief 测试查找已存在的事件 * * 验证 findEventById 能正确返回已存在的事件指针。 */ TEST_F(CmsEngineTest, testFindEventByIdExisting) { // 执行 const EventRecord* evt = engine->findEventById("EVT-001"); // 验证 ASSERT_NE(evt, nullptr); EXPECT_EQ(evt->id, "EVT-001"); EXPECT_EQ(evt->status, EventStatus::Pending); EXPECT_EQ(evt->priority, 100); } /** * @brief 测试查找不存在的事件 * * 验证 findEventById 在查找不存在的事件时返回 nullptr。 */ TEST_F(CmsEngineTest, testFindEventByIdNonExisting) { // 执行 const EventRecord* evt = engine->findEventById("NON-EXISTENT"); // 验证 EXPECT_EQ(evt, nullptr); } /** * @brief 测试查找空字符串 ID * * 验证 findEventById 在查找空字符串时返回 nullptr。 */ TEST_F(CmsEngineTest, testFindEventByIdEmptyString) { // 执行 const EventRecord* evt = engine->findEventById(""); // 验证 EXPECT_EQ(evt, nullptr); } /** * @brief 测试查找特殊字符 ID * * 验证 findEventById 能正确处理包含特殊字符的 ID。 */ TEST_F(CmsEngineTest, testFindEventByIdSpecialChars) { // 准备包含特殊字符的事件 EventRecord specialEvent; specialEvent.id = "EVT-@#$%"; specialEvent.status = EventStatus::Pending; specialEvent.priority = 50; engine->ingestEvent(specialEvent); // 执行 const EventRecord* evt = engine->findEventById("EVT-@#$%"); // 验证 ASSERT_NE(evt, nullptr); EXPECT_EQ(evt->id, "EVT-@#$%"); } /** * @brief 测试查找长 ID 字符串 * * 验证 findEventById 能正确处理超长 ID 字符串。 */ TEST_F(CmsEngineTest, testFindEventByIdLongString) { // 准备长 ID 事件 std::string longId = "EVT-" + std::string(1000, 'A'); EventRecord longEvent; longEvent.id = longId; longEvent.status = EventStatus::Pending; longEvent.priority = 75; engine->ingestEvent(longEvent); // 执行 const EventRecord* evt = engine->findEventById(longId); // 验证 ASSERT_NE(evt, nullptr); EXPECT_EQ(evt->id, longId); } /** * @brief 测试查找后修改事件状态 * * 验证通过 findEventById 返回的指针可以正确反映事件状态的变化。 */ TEST_F(CmsEngineTest, testFindEventByIdAfterStatusChange) { // 先处理事件,改变状态 engine->processPendingEvents(); // 查找事件 const EventRecord* evt = engine->findEventById("EVT-001"); // 验证状态已更新 ASSERT_NE(evt, nullptr); EXPECT_EQ(evt->status, EventStatus::Generated); } // ============================================================================ // 测试用例:createTaskPlan // ============================================================================ /** * @brief 测试正常创建任务方案 * * 验证 createTaskPlan 能正确创建有效的任务方案。 */ TEST_F(CmsEngineTest, testCreateTaskPlanNormal) { // 准备 TaskPlan plan; plan.name = "TestPlan-001"; plan.type = PlanType::Centralized; plan.status = PlanStatus::Drafting; plan.resourceQuota = 0.8; plan.constraints = "测试约束"; // 执行 bool result = engine->createTaskPlan(plan); // 验证 EXPECT_TRUE(result); // 验证 ID 已被填充 EXPECT_FALSE(plan.id.empty()); EXPECT_THAT(plan.id, StartsWith("ID-")); // 验证创建时间已被填充 auto now = std::chrono::system_clock::now(); auto diff = std::chrono::duration_cast(now - plan.createTime).count(); EXPECT_LT(diff, 5); // 创建时间应该在 5 秒内 // 验证方案已存入引擎 const std::vector& plans = engine->getAllPlans(); EXPECT_EQ(plans.size(), 1); EXPECT_EQ(plans[0].name, "TestPlan-001"); EXPECT_EQ(plans[0].id, plan.id); } /** * @brief 测试创建空名称的任务方案 * * 验证 createTaskPlan 在名称为空时返回 false。 */ TEST_F(CmsEngineTest, testCreateTaskPlanEmptyName) { // 准备空名称方案 TaskPlan plan; plan.name = ""; plan.type = PlanType::Centralized; plan.status = PlanStatus::Drafting; // 执行 bool result = engine->createTaskPlan(plan); // 验证 EXPECT_FALSE(result); // 验证方案未被加入引擎 const std::vector& plans = engine->getAllPlans(); EXPECT_TRUE(plans.empty()); } /** * @brief 测试创建多个任务方案 * * 验证 createTaskPlan 能连续创建多个方案,且 ID 自增。 */ TEST_F(CmsEngineTest, testCreateTaskPlanMultiple) { // 创建第一个方案 TaskPlan plan1; plan1.name = "Plan-001"; EXPECT_TRUE(engine->createTaskPlan(plan1)); // 创建第二个方案 TaskPlan plan2; plan2.name = "Plan-002"; EXPECT_TRUE(engine->createTaskPlan(plan2)); // 创建第三个方案 TaskPlan plan3; plan3.name = "Plan-003"; EXPECT_TRUE(engine->createTaskPlan(plan3)); // 验证方案数量 const std::vector& plans = engine->getAllPlans(); EXPECT_EQ(plans.size(), 3); // 验证 ID 自增 EXPECT_EQ(plans[0].id, "ID-00001"); EXPECT_EQ(plans[1].id, "ID-00002"); EXPECT_EQ(plans[2].id, "ID-00003"); // 验证名称正确 EXPECT_EQ(plans[0].name, "Plan-001"); EXPECT_EQ(plans[1].name, "Plan-002"); EXPECT_EQ(plans[2].name, "Plan-003"); } /** * @brief 测试创建方案后通过 ID 查找 * * 验证创建方案后可以通过 findPlanById 正确查找。 */ TEST_F(CmsEngineTest, testCreateTaskPlanAndFindById) { // 创建方案 TaskPlan plan; plan.name = "FindablePlan"; plan.type = PlanType::Distributed; plan.status = PlanStatus::Drafting; plan.resourceQuota = 0.6; EXPECT_TRUE(engine->createTaskPlan(plan)); // 通过 ID 查找 const TaskPlan* foundPlan = engine->findPlanById(plan.id); // 验证 ASSERT_NE(foundPlan, nullptr); EXPECT_EQ(foundPlan->name, "FindablePlan"); EXPECT_EQ(foundPlan->type, PlanType::Distributed); EXPECT_EQ(foundPlan->status, PlanStatus::Drafting); EXPECT_NEAR(foundPlan->resourceQuota, 0.6, 0.001); } /** * @brief 测试创建方案时带有特殊字符名称 * * 验证 createTaskPlan 能处理包含特殊字符的方案名称。 */ TEST_F(CmsEngineTest, testCreateTaskPlanSpecialName) { // 准备特殊名称 TaskPlan plan; plan.name = "Plan-@#$%^&*()_+"; plan.type = PlanType::Centralized; plan.status = PlanStatus::Drafting; // 执行 bool result = engine->createTaskPlan(plan); // 验证 EXPECT_TRUE(result); // 验证方案已存入 const std::vector& plans = engine->getAllPlans(); EXPECT_EQ(plans.size(), 1); EXPECT_EQ(plans[0].name, "Plan-@#$%^&*()_+"); } /** * @brief 测试创建方案后更新状态 * * 验证创建方案后可以更新其状态。 */ TEST_F(CmsEngineTest, testCreateTaskPlanAndUpdateStatus) { // 创建方案 TaskPlan plan; plan.name = "UpdatablePlan"; plan.type = PlanType::Centralized; plan.status = PlanStatus::Drafting; EXPECT_TRUE(engine->createTaskPlan(plan)); // 更新状态 bool updateResult = engine->updatePlanStatus(plan.id, PlanStatus::Drafting); EXPECT_TRUE(updateResult); // 验证状态已更新 const TaskPlan* updatedPlan = engine->findPlanById(plan.id); ASSERT_NE(updatedPlan, nullptr); EXPECT_EQ(updatedPlan->status, PlanStatus::Drafting); } /** * @brief 测试创建方案时传入已填充 ID 的方案 * * 验证 createTaskPlan 会覆盖传入方案的 ID。 */ TEST_F(CmsEngineTest, testCreateTaskPlanWithPreFilledId) { // 准备已填充 ID 的方案 TaskPlan plan; plan.id = "PRE-FILLED-ID"; plan.name = "TestPlan"; plan.type = PlanType::Centralized; plan.status = PlanStatus::Drafting; // 执行 bool result = engine->createTaskPlan(plan); // 验证 EXPECT_TRUE(result); // 验证 ID 已被覆盖 EXPECT_NE(plan.id, "PRE-FILLED-ID"); EXPECT_THAT(plan.id, StartsWith("ID-")); }