diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..4750de7 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.10.0) +project(test_task_plan_2) +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_task_plan_2 test_dispatch_monitor.cpp ../src/core/dispatch.cpp test_event_processor.cpp ../src/core/event.cpp) + +target_link_libraries(test_task_plan_2 gtest gmock gtest_main) +include(GoogleTest) +gtest_discover_tests(test_task_plan_2) \ No newline at end of file diff --git a/tests/test_dispatch_monitor.cpp b/tests/test_dispatch_monitor.cpp new file mode 100644 index 0000000..d8548c1 --- /dev/null +++ b/tests/test_dispatch_monitor.cpp @@ -0,0 +1,184 @@ +#include +#include "core/dispatch.hpp" +#include +#include +#include +#include + +// 为保持测试独立可编译,此处提供依赖结构体的最小化定义 +// 实际项目中应直接包含对应头文件 +namespace battlefield { +struct Plan { + std::string id; + std::string name; + std::vector subTasks; +}; +struct CmdPacket { + std::string packetId; + std::string planId; + std::string targetUnit; + std::string payload; + std::chrono::system_clock::time_point issueTime; +}; +struct MonitorStatus { + int32_t totalTasks = 0; + int32_t completedTasks = 0; + int32_t inProgressTasks = 0; + int32_t failedTasks = 0; + double progressPercent = 0.0; +}; +struct DispatchLog { + std::string logId; + std::string planId; + std::string action; + std::chrono::system_clock::time_point timestamp; + bool success; +}; + +class DispatchMonitor { +public: + CmdPacket DispatchPlan(const Plan& plan, const std::string& targetUnit); + MonitorStatus GetMonitorStatus() const; + std::string GetDashboardData() const; + void LogDispatch(const std::string& planId, const std::string& action, bool success); + void AdvanceProgress(int32_t completed); +private: + std::vector issuedPackets_; + std::vector logs_; + MonitorStatus status_; +}; +} // namespace battlefield + +// 测试夹具 +class DispatchMonitorTest : public ::testing::Test { +protected: + void SetUp() override { + monitor_ = std::make_unique(); + } + void TearDown() override { + monitor_.reset(); + } + std::unique_ptr monitor_; +}; + +// ==================== DispatchPlan 测试 ==================== +TEST_F(DispatchMonitorTest, testDispatchPlanNormalInput) { + // 正常输入:包含多个子任务的计划 + battlefield::Plan plan{"P001", "Attack Plan", {"Task1", "Task2", "Task3"}}; + std::string target = "UnitAlpha"; + + auto packet = monitor_->DispatchPlan(plan, target); + + // 验证返回值 + EXPECT_EQ(packet.packetId, "CMD-P001"); + EXPECT_EQ(packet.planId, "P001"); + EXPECT_EQ(packet.targetUnit, "UnitAlpha"); + EXPECT_TRUE(packet.payload.find("Attack Plan") != std::string::npos); + EXPECT_TRUE(packet.payload.find("3") != std::string::npos); + + // 验证副作用:状态更新 + auto status = monitor_->GetMonitorStatus(); + EXPECT_EQ(status.totalTasks, 3); + EXPECT_EQ(status.inProgressTasks, 3); + EXPECT_EQ(status.completedTasks, 0); +} + +TEST_F(DispatchMonitorTest, testDispatchPlanBoundaryZeroTasks) { + // 边界值测试:空子任务列表 + battlefield::Plan plan{"P002", "Empty Plan", {}}; + auto packet = monitor_->DispatchPlan(plan, "UnitBeta"); + + EXPECT_EQ(packet.packetId, "CMD-P002"); + auto status = monitor_->GetMonitorStatus(); + EXPECT_EQ(status.totalTasks, 0); + EXPECT_EQ(status.inProgressTasks, 0); +} + +// ==================== GetMonitorStatus 测试 ==================== +TEST_F(DispatchMonitorTest, testGetMonitorStatusInitialState) { + // 正常输入:初始状态验证 + auto status = monitor_->GetMonitorStatus(); + EXPECT_EQ(status.totalTasks, 0); + EXPECT_EQ(status.completedTasks, 0); + EXPECT_EQ(status.inProgressTasks, 0); + EXPECT_EQ(status.failedTasks, 0); + EXPECT_DOUBLE_EQ(status.progressPercent, 0.0); +} + +// ==================== GetDashboardData 测试 ==================== +TEST_F(DispatchMonitorTest, testGetDashboardDataNormalFormat) { + // 正常输入:执行部分操作后验证仪表盘格式 + battlefield::Plan plan{"P003", "Test Plan", {"T1", "T2"}}; + monitor_->DispatchPlan(plan, "UnitGamma"); + monitor_->AdvanceProgress(1); + + std::string dashboard = monitor_->GetDashboardData(); + EXPECT_TRUE(dashboard.find("=== Dashboard ===") != std::string::npos); + EXPECT_TRUE(dashboard.find("Total Tasks: 2") != std::string::npos); + EXPECT_TRUE(dashboard.find("Completed: 1") != std::string::npos); + EXPECT_TRUE(dashboard.find("In Progress: 1") != std::string::npos); + EXPECT_TRUE(dashboard.find("Progress: 50.0%") != std::string::npos); + EXPECT_TRUE(dashboard.find("Issued Packets: 1") != std::string::npos); + EXPECT_TRUE(dashboard.find("Log Entries: 1") != std::string::npos); +} + +TEST_F(DispatchMonitorTest, testGetDashboardDataEmptyState) { + // 边界值测试:空状态下的仪表盘输出 + std::string dashboard = monitor_->GetDashboardData(); + EXPECT_TRUE(dashboard.find("Total Tasks: 0") != std::string::npos); + EXPECT_TRUE(dashboard.find("Progress: 0.0%") != std::string::npos); + EXPECT_TRUE(dashboard.find("Issued Packets: 0") != std::string::npos); +} + +// ==================== LogDispatch 测试 ==================== +TEST_F(DispatchMonitorTest, testLogDispatchNormalSuccess) { + // 正常输入:记录成功日志 + monitor_->LogDispatch("P004", "START", true); + std::string dash = monitor_->GetDashboardData(); + EXPECT_TRUE(dash.find("Log Entries: 1") != std::string::npos); +} + +TEST_F(DispatchMonitorTest, testLogDispatchBoundaryEmptyStrings) { + // 边界值测试:空字符串参数 + monitor_->LogDispatch("", "", false); + std::string dash = monitor_->GetDashboardData(); + EXPECT_TRUE(dash.find("Log Entries: 1") != std::string::npos); + // 验证日志ID自增逻辑正常 + monitor_->LogDispatch("P005", "END", true); + dash = monitor_->GetDashboardData(); + EXPECT_TRUE(dash.find("Log Entries: 2") != std::string::npos); +} + +// ==================== AdvanceProgress 测试 ==================== +TEST_F(DispatchMonitorTest, testAdvanceProgressNormal) { + // 正常输入:正常推进进度 + battlefield::Plan plan{"P005", "Progress Plan", {"A", "B", "C", "D"}}; + monitor_->DispatchPlan(plan, "UnitDelta"); + monitor_->AdvanceProgress(2); + + auto status = monitor_->GetMonitorStatus(); + EXPECT_EQ(status.completedTasks, 2); + EXPECT_EQ(status.inProgressTasks, 2); + EXPECT_DOUBLE_EQ(status.progressPercent, 50.0); +} + +TEST_F(DispatchMonitorTest, testAdvanceProgressBoundaryClamping) { + // 边界值测试:完成数大于进行中任务数(触发截断) + battlefield::Plan plan{"P006", "Clamp Plan", {"X", "Y"}}; + monitor_->DispatchPlan(plan, "UnitEpsilon"); + monitor_->AdvanceProgress(10); // 10 > 2 + + auto status = monitor_->GetMonitorStatus(); + EXPECT_EQ(status.completedTasks, 2); + EXPECT_EQ(status.inProgressTasks, 0); + EXPECT_DOUBLE_EQ(status.progressPercent, 100.0); +} + +TEST_F(DispatchMonitorTest, testAdvanceProgressSpecialZeroTotal) { + // 特殊场景测试:总任务数为0时避免除零异常 + monitor_->AdvanceProgress(5); + auto status = monitor_->GetMonitorStatus(); + // inProgressTasks 初始为0,min(5, 0) = 0,故 completedTasks 不变 + EXPECT_EQ(status.completedTasks, 0); + EXPECT_DOUBLE_EQ(status.progressPercent, 0.0); +} diff --git a/tests/test_event_processor.cpp b/tests/test_event_processor.cpp new file mode 100644 index 0000000..5da2e9f --- /dev/null +++ b/tests/test_event_processor.cpp @@ -0,0 +1,105 @@ +#include +#include "core/event.hpp" +#include +#include +#include +#include + +namespace battlefield { + +class EventProcessorTest : public ::testing::Test { +protected: + void SetUp() override { + processor_ = std::make_unique(); + } + + void TearDown() override { + processor_.reset(); + } + + std::unique_ptr processor_; +}; + +// ================= ReceiveEvent 测试用例 ================= + +TEST_F(EventProcessorTest, testReceiveEventNormalInput) { + std::string rawJson = "ABCD1234,extra_data"; + EXPECT_TRUE(processor_->ReceiveEvent(rawJson)); + auto pending = processor_->GetPendingEvents(); + EXPECT_EQ(pending.size(), 1); + EXPECT_EQ(pending[0].id, "EVT-ABCD"); +} + +TEST_F(EventProcessorTest, testReceiveEventEmptyBoundary) { + std::string rawJson = ""; + EXPECT_THROW(processor_->ReceiveEvent(rawJson), std::out_of_range); +} + +TEST_F(EventProcessorTest, testReceiveEventShortException) { + std::string rawJson = "ABC,data"; + EXPECT_THROW(processor_->ReceiveEvent(rawJson), std::out_of_range); +} + +// ================= TransformEvent 测试用例 ================= + +TEST_F(EventProcessorTest, testTransformEventNormalInput) { + std::string raw = "WXYZ,metadata"; + Event evt = processor_->TransformEvent(raw); + EXPECT_EQ(evt.id, "EVT-WXYZ"); + EXPECT_EQ(evt.type, EventType::INTEL); + EXPECT_EQ(evt.priority, 5); + EXPECT_EQ(evt.location, "zone-alpha"); + EXPECT_EQ(evt.status, EventStatus::PENDING); +} + +TEST_F(EventProcessorTest, testTransformEventBoundaryInput) { + std::string raw = "1234"; + Event evt = processor_->TransformEvent(raw); + EXPECT_EQ(evt.id, "EVT-1234"); +} + +TEST_F(EventProcessorTest, testTransformEventShortException) { + std::string raw = "123"; + EXPECT_THROW(processor_->TransformEvent(raw), std::out_of_range); +} + +// ================= GetPendingEvents 测试用例 ================= + +TEST_F(EventProcessorTest, testGetPendingEventsEmptyBoundary) { + auto pending = processor_->GetPendingEvents(); + EXPECT_TRUE(pending.empty()); +} + +TEST_F(EventProcessorTest, testGetPendingEventsNormalFilter) { + processor_->ReceiveEvent("AAAA,data"); + processor_->ReceiveEvent("BBBB,data"); + auto pending = processor_->GetPendingEvents(); + EXPECT_EQ(pending.size(), 2); + EXPECT_EQ(pending[0].id, "EVT-AAAA"); + EXPECT_EQ(pending[1].id, "EVT-BBBB"); +} + +// ================= SortEventsByPriority 测试用例 ================= + +TEST_F(EventProcessorTest, testSortEventsByPriorityAscendingNormal) { + processor_->ReceiveEvent("AAAA,data"); + processor_->ReceiveEvent("BBBB,data"); + processor_->SortEventsByPriority(true); + auto events = processor_->GetPendingEvents(); + EXPECT_EQ(events.size(), 2); +} + +TEST_F(EventProcessorTest, testSortEventsByPriorityDescendingNormal) { + processor_->ReceiveEvent("CCCC,data"); + processor_->SortEventsByPriority(false); + auto events = processor_->GetPendingEvents(); + EXPECT_EQ(events.size(), 1); +} + +TEST_F(EventProcessorTest, testSortEventsByPriorityEmptyBoundary) { + processor_->SortEventsByPriority(true); + auto events = processor_->GetPendingEvents(); + EXPECT_TRUE(events.empty()); +} + +} // namespace battlefield