#include #include #include "app.hpp" #include #include #include using namespace testing; // ============================================================================ // Test Fixture for CmsEngine // ============================================================================ class CmsEngineTest : public ::testing::Test { protected: void SetUp() override { engine = new CmsEngine(); } void TearDown() override { delete engine; } CmsEngine* engine; }; // ============================================================================ // Tests for CmsEngine constructor // ============================================================================ /** * @brief Test: Constructor initializes system context correctly * * Verifies that after construction: * - currentMode is RunMode::Idle * - consistencyMark is 0 * - switchTime is set (not default) * - contextSnapshot contains expected JSON */ TEST_F(CmsEngineTest, testConstructorInitializesSystemContext) { const auto& ctx = engine->getSystemContext(); EXPECT_EQ(ctx.currentMode, RunMode::Idle); EXPECT_EQ(ctx.consistencyMark, 0); EXPECT_NE(ctx.switchTime, std::chrono::system_clock::time_point()); EXPECT_THAT(ctx.contextSnapshot, HasSubstr("Idle")); EXPECT_THAT(ctx.contextSnapshot, HasSubstr("1.0.0")); } /** * @brief Test: Constructor initializes empty containers * * Verifies that all internal containers are empty after construction. */ TEST_F(CmsEngineTest, testConstructorInitializesEmptyContainers) { EXPECT_EQ(engine->getAllPlans().size(), 0); EXPECT_EQ(engine->getUnreadNotifications().size(), 0); EXPECT_EQ(engine->getSummary().find("Events : 0"), std::string::npos); } // ============================================================================ // Tests for ingestEvent // ============================================================================ /** * @brief Test: Ingest event with valid data succeeds * * Creates a valid EventRecord with non-empty ID and priority <= 255. * Expects ingestEvent to return true. */ TEST_F(CmsEngineTest, testIngestEventValidData) { EventRecord event; event.id = "EVT-001"; event.priority = 100; event.status = EventStatus::Pending; EXPECT_TRUE(engine->ingestEvent(event)); } /** * @brief Test: Ingest event with empty ID fails * * Verifies that an event with an empty ID is rejected. */ TEST_F(CmsEngineTest, testIngestEventEmptyId) { EventRecord event; event.id = ""; event.priority = 100; EXPECT_FALSE(engine->ingestEvent(event)); } /** * @brief Test: Ingest event with priority > 255 fails * * Verifies that an event with priority exceeding 255 is rejected. */ TEST_F(CmsEngineTest, testIngestEventPriorityExceedsMax) { EventRecord event; event.id = "EVT-002"; event.priority = 256; EXPECT_FALSE(engine->ingestEvent(event)); } /** * @brief Test: Ingest event with priority = 0 succeeds (boundary) * * Verifies that an event with minimum priority (0) is accepted. */ TEST_F(CmsEngineTest, testIngestEventPriorityZero) { EventRecord event; event.id = "EVT-003"; event.priority = 0; EXPECT_TRUE(engine->ingestEvent(event)); } /** * @brief Test: Ingest event with priority = 255 succeeds (boundary) * * Verifies that an event with maximum valid priority (255) is accepted. */ TEST_F(CmsEngineTest, testIngestEventPriorityMax) { EventRecord event; event.id = "EVT-004"; event.priority = 255; EXPECT_TRUE(engine->ingestEvent(event)); } /** * @brief Test: Ingest multiple events and verify storage * * Ingests multiple events and checks that they are stored correctly. */ TEST_F(CmsEngineTest, testIngestMultipleEvents) { EventRecord event1; event1.id = "EVT-001"; event1.priority = 10; EXPECT_TRUE(engine->ingestEvent(event1)); EventRecord event2; event2.id = "EVT-002"; event2.priority = 20; EXPECT_TRUE(engine->ingestEvent(event2)); // Verify events are stored by checking processPendingEvents count EXPECT_EQ(engine->processPendingEvents(), 2); } // ============================================================================ // Tests for processPendingEvents // ============================================================================ /** * @brief Test: Process pending events with no events * * When there are no events in the system, processPendingEvents should return 0. */ TEST_F(CmsEngineTest, testProcessPendingEventsNoEvents) { EXPECT_EQ(engine->processPendingEvents(), 0); } /** * @brief Test: Process pending events with one pending event * * Ingests one pending event and verifies that processPendingEvents processes it. */ TEST_F(CmsEngineTest, testProcessPendingEventsOnePending) { EventRecord event; event.id = "EVT-001"; event.priority = 50; event.status = EventStatus::Pending; engine->ingestEvent(event); EXPECT_EQ(engine->processPendingEvents(), 1); } /** * @brief Test: Process pending events with non-pending events only * * Events with status other than Pending should not be processed. */ TEST_F(CmsEngineTest, testProcessPendingEventsNonPendingOnly) { EventRecord event; event.id = "EVT-001"; event.priority = 50; event.status = EventStatus::Generated; engine->ingestEvent(event); EXPECT_EQ(engine->processPendingEvents(), 0); } /** * @brief Test: Process pending events changes status to Generated * * After processing, the event status should be changed to Generated. */ TEST_F(CmsEngineTest, testProcessPendingEventsChangesStatus) { EventRecord event; event.id = "EVT-001"; event.priority = 50; event.status = EventStatus::Pending; engine->ingestEvent(event); engine->processPendingEvents(); const EventRecord* processedEvent = engine->findEventById("EVT-001"); ASSERT_NE(processedEvent, nullptr); EXPECT_EQ(processedEvent->status, EventStatus::Generated); } /** * @brief Test: Process pending events creates TaskPlan * * Verifies that a TaskPlan is created for each processed event. */ TEST_F(CmsEngineTest, testProcessPendingEventsCreatesPlan) { EventRecord event; event.id = "EVT-001"; event.priority = 50; event.status = EventStatus::Pending; engine->ingestEvent(event); engine->processPendingEvents(); const auto& plans = engine->getAllPlans(); ASSERT_EQ(plans.size(), 1); EXPECT_EQ(plans[0].relatedEventId, "EVT-001"); EXPECT_EQ(plans[0].status, PlanStatus::Drafting); EXPECT_EQ(plans[0].type, PlanType::Centralized); EXPECT_EQ(plans[0].resourceQuota, 0.5); EXPECT_EQ(plans[0].constraints, "自动生成约束"); } /** * @brief Test: Process pending events with multiple pending events * * Verifies that all pending events are processed correctly. */ TEST_F(CmsEngineTest, testProcessPendingEventsMultiple) { EventRecord event1; event1.id = "EVT-001"; event1.priority = 10; event1.status = EventStatus::Pending; engine->ingestEvent(event1); EventRecord event2; event2.id = "EVT-002"; event2.priority = 20; event2.status = EventStatus::Pending; engine->ingestEvent(event2); EventRecord event3; event3.id = "EVT-003"; event3.priority = 30; event3.status = EventStatus::Generated; // Not pending engine->ingestEvent(event3); EXPECT_EQ(engine->processPendingEvents(), 2); const auto& plans = engine->getAllPlans(); EXPECT_EQ(plans.size(), 2); } /** * @brief Test: Process pending events generates unique IDs * * Verifies that each generated TaskPlan has a unique ID. */ TEST_F(CmsEngineTest, testProcessPendingEventsUniqueIds) { EventRecord event1; event1.id = "EVT-001"; event1.priority = 10; event1.status = EventStatus::Pending; engine->ingestEvent(event1); EventRecord event2; event2.id = "EVT-002"; event2.priority = 20; event2.status = EventStatus::Pending; engine->ingestEvent(event2); engine->processPendingEvents(); const auto& plans = engine->getAllPlans(); EXPECT_NE(plans[0].id, plans[1].id); } /** * @brief Test: Process pending events twice does not reprocess * * After processing, events should not be processed again. */ TEST_F(CmsEngineTest, testProcessPendingEventsIdempotent) { EventRecord event; event.id = "EVT-001"; event.priority = 50; event.status = EventStatus::Pending; engine->ingestEvent(event); EXPECT_EQ(engine->processPendingEvents(), 1); EXPECT_EQ(engine->processPendingEvents(), 0); } /** * @brief Test: Process pending events with empty event ID (should not be ingested) * * Events with empty IDs are rejected by ingestEvent, so they won't be processed. */ TEST_F(CmsEngineTest, testProcessPendingEventsEmptyIdNotIngested) { EventRecord event; event.id = ""; event.priority = 50; event.status = EventStatus::Pending; engine->ingestEvent(event); // Should return false EXPECT_EQ(engine->processPendingEvents(), 0); } /** * @brief Test: Process pending events with high priority event * * Verifies that events with high priority (up to 255) are processed correctly. */ TEST_F(CmsEngineTest, testProcessPendingEventsHighPriority) { EventRecord event; event.id = "EVT-001"; event.priority = 255; event.status = EventStatus::Pending; engine->ingestEvent(event); EXPECT_EQ(engine->processPendingEvents(), 1); const auto& plans = engine->getAllPlans(); EXPECT_EQ(plans[0].relatedEventId, "EVT-001"); }