diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..4cb68f5 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.10.0) +project(test_plan_execute_t1) +include(FetchContent) +if (MSVC) + add_compile_options(/utf-8) +endif() +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) + +include(CTest) +enable_testing() + +add_executable(test_plan_execute_t1 test_app.cpp ../src/app.cpp) + +target_link_libraries(test_plan_execute_t1 gtest gmock gtest_main) +include(GoogleTest) +gtest_discover_tests(test_plan_execute_t1) \ No newline at end of file diff --git a/tests/test_app.cpp b/tests/test_app.cpp new file mode 100644 index 0000000..5bcddf6 --- /dev/null +++ b/tests/test_app.cpp @@ -0,0 +1,326 @@ +#include +#include "app.hpp" +#include +#include + +// ============================================================ +// 测试夹具:CmsEngineTest +// ============================================================ +class CmsEngineTest : public ::testing::Test { +protected: + CmsEngine engine; + + void SetUp() override { + // 每个测试用例开始前重置引擎状态 + } + + void TearDown() override { + // 每个测试用例结束后清理 + } +}; + +// ============================================================ +// ingestEvent 测试 +// ============================================================ + +/** + * @brief 测试 ingestEvent 正常输入:有效事件应返回 true + */ +TEST_F(CmsEngineTest, testIngestEventNormal) { + EventRecord event; + event.id = "EVT-001"; + event.priority = 100; + event.status = EventStatus::Pending; + + bool result = engine.ingestEvent(event); + EXPECT_TRUE(result); + + // 验证事件已存入 + const EventRecord* found = engine.findEventById("EVT-001"); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->id, "EVT-001"); + EXPECT_EQ(found->priority, 100); + EXPECT_EQ(found->status, EventStatus::Pending); +} + +/** + * @brief 测试 ingestEvent 空 ID:应返回 false + */ +TEST_F(CmsEngineTest, testIngestEventEmptyId) { + EventRecord event; + event.id = ""; + event.priority = 50; + + bool result = engine.ingestEvent(event); + EXPECT_FALSE(result); + + // 验证事件未存入 + const EventRecord* found = engine.findEventById(""); + EXPECT_EQ(found, nullptr); +} + +/** + * @brief 测试 ingestEvent 优先级边界:优先级为 0 应成功 + */ +TEST_F(CmsEngineTest, testIngestEventPriorityMin) { + EventRecord event; + event.id = "EVT-002"; + event.priority = 0; + + bool result = engine.ingestEvent(event); + EXPECT_TRUE(result); + + const EventRecord* found = engine.findEventById("EVT-002"); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->priority, 0); +} + +/** + * @brief 测试 ingestEvent 优先级边界:优先级为 255 应成功 + */ +TEST_F(CmsEngineTest, testIngestEventPriorityMax) { + EventRecord event; + event.id = "EVT-003"; + event.priority = 255; + + bool result = engine.ingestEvent(event); + EXPECT_TRUE(result); + + const EventRecord* found = engine.findEventById("EVT-003"); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->priority, 255); +} + +/** + * @brief 测试 ingestEvent 优先级越界:优先级为 256 应返回 false + */ +TEST_F(CmsEngineTest, testIngestEventPriorityOverflow) { + EventRecord event; + event.id = "EVT-004"; + event.priority = 256; + + bool result = engine.ingestEvent(event); + EXPECT_FALSE(result); + + const EventRecord* found = engine.findEventById("EVT-004"); + EXPECT_EQ(found, nullptr); +} + +/** + * @brief 测试 ingestEvent 多次接入同一事件 ID:应允许重复 ID + */ +TEST_F(CmsEngineTest, testIngestEventDuplicateId) { + EventRecord event1; + event1.id = "EVT-005"; + event1.priority = 10; + + EventRecord event2; + event2.id = "EVT-005"; + event2.priority = 20; + + bool result1 = engine.ingestEvent(event1); + bool result2 = engine.ingestEvent(event2); + EXPECT_TRUE(result1); + EXPECT_TRUE(result2); + + // 验证两个事件都存入(findEventById 返回第一个匹配的) + const EventRecord* found = engine.findEventById("EVT-005"); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->priority, 10); +} + +// ============================================================ +// processPendingEvents 测试 +// ============================================================ + +/** + * @brief 测试 processPendingEvents 无待处理事件:应返回 0 + */ +TEST_F(CmsEngineTest, testProcessPendingEventsNoPending) { + // 先接入一个非 Pending 状态的事件 + EventRecord event; + event.id = "EVT-010"; + event.priority = 50; + event.status = EventStatus::Generated; + engine.ingestEvent(event); + + size_t count = engine.processPendingEvents(); + EXPECT_EQ(count, 0); +} + +/** + * @brief 测试 processPendingEvents 单个待处理事件:应返回 1 + */ +TEST_F(CmsEngineTest, testProcessPendingEventsSingle) { + EventRecord event; + event.id = "EVT-011"; + event.priority = 50; + event.status = EventStatus::Pending; + engine.ingestEvent(event); + + size_t count = engine.processPendingEvents(); + EXPECT_EQ(count, 1); + + // 验证事件状态已更新 + const EventRecord* found = engine.findEventById("EVT-011"); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->status, EventStatus::Generated); + + // 验证生成了对应的 TaskPlan + const auto& plans = engine.getAllPlans(); + ASSERT_EQ(plans.size(), 1); + EXPECT_EQ(plans[0].relatedEventId, "EVT-011"); + EXPECT_EQ(plans[0].name, "AutoPlan-EVT-011"); + EXPECT_EQ(plans[0].type, PlanType::Centralized); + EXPECT_EQ(plans[0].status, PlanStatus::Drafting); + EXPECT_FALSE(plans[0].id.empty()); + EXPECT_EQ(plans[0].resourceQuota, 0.5); + EXPECT_EQ(plans[0].constraints, "自动生成约束"); +} + +/** + * @brief 测试 processPendingEvents 多个待处理事件:应返回正确计数 + */ +TEST_F(CmsEngineTest, testProcessPendingEventsMultiple) { + // 接入 3 个 Pending 事件和 1 个非 Pending 事件 + for (int i = 0; i < 3; ++i) { + EventRecord event; + event.id = "EVT-MULTI-" + std::to_string(i); + event.priority = 50; + event.status = EventStatus::Pending; + engine.ingestEvent(event); + } + + EventRecord nonPending; + nonPending.id = "EVT-MULTI-NON"; + nonPending.priority = 50; + nonPending.status = EventStatus::Generated; + engine.ingestEvent(nonPending); + + size_t count = engine.processPendingEvents(); + EXPECT_EQ(count, 3); + + // 验证所有 Pending 事件都已处理 + for (int i = 0; i < 3; ++i) { + std::string id = "EVT-MULTI-" + std::to_string(i); + const EventRecord* found = engine.findEventById(id); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->status, EventStatus::Generated); + } + + // 验证生成了 3 个 TaskPlan + const auto& plans = engine.getAllPlans(); + ASSERT_EQ(plans.size(), 3); +} + +/** + * @brief 测试 processPendingEvents 空事件库:应返回 0 + */ +TEST_F(CmsEngineTest, testProcessPendingEventsEmpty) { + size_t count = engine.processPendingEvents(); + EXPECT_EQ(count, 0); +} + +/** + * @brief 测试 processPendingEvents 重复调用:第二次应返回 0 + */ +TEST_F(CmsEngineTest, testProcessPendingEventsIdempotent) { + EventRecord event; + event.id = "EVT-012"; + event.priority = 50; + event.status = EventStatus::Pending; + engine.ingestEvent(event); + + size_t count1 = engine.processPendingEvents(); + EXPECT_EQ(count1, 1); + + size_t count2 = engine.processPendingEvents(); + EXPECT_EQ(count2, 0); +} + +// ============================================================ +// findEventById 测试 +// ============================================================ + +/** + * @brief 测试 findEventById 正常查找:应返回正确的事件指针 + */ +TEST_F(CmsEngineTest, testFindEventByIdNormal) { + EventRecord event; + event.id = "EVT-100"; + event.priority = 80; + event.status = EventStatus::Pending; + engine.ingestEvent(event); + + const EventRecord* found = engine.findEventById("EVT-100"); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->id, "EVT-100"); + EXPECT_EQ(found->priority, 80); + EXPECT_EQ(found->status, EventStatus::Pending); +} + +/** + * @brief 测试 findEventById 不存在的 ID:应返回 nullptr + */ +TEST_F(CmsEngineTest, testFindEventByIdNotFound) { + const EventRecord* found = engine.findEventById("NONEXISTENT"); + EXPECT_EQ(found, nullptr); +} + +/** + * @brief 测试 findEventById 空字符串:应返回 nullptr + */ +TEST_F(CmsEngineTest, testFindEventByIdEmptyString) { + const EventRecord* found = engine.findEventById(""); + EXPECT_EQ(found, nullptr); +} + +/** + * @brief 测试 findEventById 多个事件中查找:应返回第一个匹配的 + */ +TEST_F(CmsEngineTest, testFindEventByIdMultipleEvents) { + EventRecord event1; + event1.id = "EVT-200"; + event1.priority = 10; + engine.ingestEvent(event1); + + EventRecord event2; + event2.id = "EVT-201"; + event2.priority = 20; + engine.ingestEvent(event2); + + EventRecord event3; + event3.id = "EVT-202"; + event3.priority = 30; + engine.ingestEvent(event3); + + const EventRecord* found = engine.findEventById("EVT-201"); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->id, "EVT-201"); + EXPECT_EQ(found->priority, 20); +} + +/** + * @brief 测试 findEventById 在空事件库中查找:应返回 nullptr + */ +TEST_F(CmsEngineTest, testFindEventByIdEmptyStore) { + const EventRecord* found = engine.findEventById("ANY"); + EXPECT_EQ(found, nullptr); +} + +/** + * @brief 测试 findEventById 查找已处理事件:应返回正确指针 + */ +TEST_F(CmsEngineTest, testFindEventByIdAfterProcessing) { + EventRecord event; + event.id = "EVT-300"; + event.priority = 50; + event.status = EventStatus::Pending; + engine.ingestEvent(event); + + engine.processPendingEvents(); + + const EventRecord* found = engine.findEventById("EVT-300"); + ASSERT_NE(found, nullptr); + EXPECT_EQ(found->status, EventStatus::Generated); +}