Compare commits
2 Commits
main
...
test_20260
| Author | SHA1 | Date |
|---|---|---|
|
|
3188716329 | |
|
|
d51cf330aa |
|
|
@ -30,9 +30,17 @@ MonitorStatus DispatchMonitor::GetMonitorStatus() const {
|
||||||
std::string DispatchMonitor::GetDashboardData() const {
|
std::string DispatchMonitor::GetDashboardData() const {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||||
ss << "=== Dashboard ===\n"
|
ss << "=== Dashboard ===\n";
|
||||||
<< "Time: " << std::put_time(std::gmtime(&now), "%Y-%m-%d %H:%M:%S") << "\n"
|
|
||||||
<< "Total Tasks: " << status_.totalTasks << "\n"
|
// Handle potential null pointer from gmtime
|
||||||
|
std::tm* tm_info = std::gmtime(&now);
|
||||||
|
if (tm_info != nullptr) {
|
||||||
|
ss << "Time: " << std::put_time(tm_info, "%Y-%m-%d %H:%M:%S") << "\n";
|
||||||
|
} else {
|
||||||
|
ss << "Time: UNAVAILABLE\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
ss << "Total Tasks: " << status_.totalTasks << "\n"
|
||||||
<< "Completed: " << status_.completedTasks << "\n"
|
<< "Completed: " << status_.completedTasks << "\n"
|
||||||
<< "In Progress: " << status_.inProgressTasks << "\n"
|
<< "In Progress: " << status_.inProgressTasks << "\n"
|
||||||
<< "Failed: " << status_.failedTasks << "\n"
|
<< "Failed: " << status_.failedTasks << "\n"
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,11 @@
|
||||||
namespace battlefield {
|
namespace battlefield {
|
||||||
|
|
||||||
bool EventProcessor::ReceiveEvent(const std::string& rawJson) {
|
bool EventProcessor::ReceiveEvent(const std::string& rawJson) {
|
||||||
|
// 检查输入是否为空
|
||||||
|
if (rawJson.empty()) {
|
||||||
|
throw std::out_of_range("Input string is empty");
|
||||||
|
}
|
||||||
|
|
||||||
// 模拟接收:将原始 JSON 转化为 Event 对象并加入列表
|
// 模拟接收:将原始 JSON 转化为 Event 对象并加入列表
|
||||||
Event evt = TransformEvent(rawJson);
|
Event evt = TransformEvent(rawJson);
|
||||||
events_.push_back(evt);
|
events_.push_back(evt);
|
||||||
|
|
@ -18,6 +23,12 @@ Event EventProcessor::TransformEvent(const std::string& raw) {
|
||||||
std::stringstream ss(raw);
|
std::stringstream ss(raw);
|
||||||
std::string token;
|
std::string token;
|
||||||
std::getline(ss, token, ',');
|
std::getline(ss, token, ',');
|
||||||
|
|
||||||
|
// 检查输入是否有效:需要至少4个字符才能生成有效的ID
|
||||||
|
if (token.empty() || token.size() < 4) {
|
||||||
|
throw std::out_of_range("Input string too short to generate event ID");
|
||||||
|
}
|
||||||
|
|
||||||
evt.id = "EVT-" + token.substr(0, 4);
|
evt.id = "EVT-" + token.substr(0, 4);
|
||||||
evt.type = EventType::INTEL;
|
evt.type = EventType::INTEL;
|
||||||
evt.priority = 5;
|
evt.priority = 5;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -0,0 +1,190 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "core/dispatch.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
// 使用实际项目中的类型定义
|
||||||
|
namespace battlefield {
|
||||||
|
// 使用实际项目中的类型,通过已包含的头文件获取
|
||||||
|
// struct Plan;
|
||||||
|
// struct CmdPacket;
|
||||||
|
// struct MonitorStatus;
|
||||||
|
// struct DispatchLog;
|
||||||
|
// class DispatchMonitor;
|
||||||
|
} // namespace battlefield
|
||||||
|
|
||||||
|
// 测试夹具
|
||||||
|
class DispatchMonitorTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp() override {
|
||||||
|
monitor_ = std::make_unique<battlefield::DispatchMonitor>();
|
||||||
|
}
|
||||||
|
void TearDown() override {
|
||||||
|
monitor_.reset();
|
||||||
|
}
|
||||||
|
std::unique_ptr<battlefield::DispatchMonitor> monitor_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== DispatchPlan 测试 ====================
|
||||||
|
TEST_F(DispatchMonitorTest, testDispatchPlanNormalInput) {
|
||||||
|
// 正常输入:包含多个子任务的计划
|
||||||
|
battlefield::Plan plan;
|
||||||
|
plan.id = "P001";
|
||||||
|
plan.name = "Attack Plan";
|
||||||
|
plan.description = "Test description";
|
||||||
|
plan.subTasks = {
|
||||||
|
{"Task1", "P001", "Task1", "Description 1", 0, ""},
|
||||||
|
{"Task2", "P001", "Task2", "Description 2", 1, ""},
|
||||||
|
{"Task3", "P001", "Task3", "Description 3", 2, ""}
|
||||||
|
};
|
||||||
|
plan.score = 0.0;
|
||||||
|
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;
|
||||||
|
plan.id = "P002";
|
||||||
|
plan.name = "Empty Plan";
|
||||||
|
plan.description = "Test description";
|
||||||
|
plan.subTasks = {};
|
||||||
|
plan.score = 0.0;
|
||||||
|
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;
|
||||||
|
plan.id = "P003";
|
||||||
|
plan.name = "Test Plan";
|
||||||
|
plan.description = "Test description";
|
||||||
|
plan.subTasks = {
|
||||||
|
{"T1", "P003", "Task 1", "Description 1", 0, ""},
|
||||||
|
{"T2", "P003", "Task 2", "Description 2", 1, ""}
|
||||||
|
};
|
||||||
|
plan.score = 0.0;
|
||||||
|
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;
|
||||||
|
plan.id = "P005";
|
||||||
|
plan.name = "Progress Plan";
|
||||||
|
plan.description = "Test description";
|
||||||
|
plan.subTasks = {
|
||||||
|
{"A", "P005", "Task A", "Description A", 0, ""},
|
||||||
|
{"B", "P005", "Task B", "Description B", 1, ""},
|
||||||
|
{"C", "P005", "Task C", "Description C", 2, ""},
|
||||||
|
{"D", "P005", "Task D", "Description D", 3, ""}
|
||||||
|
};
|
||||||
|
plan.score = 0.0;
|
||||||
|
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;
|
||||||
|
plan.id = "P006";
|
||||||
|
plan.name = "Clamp Plan";
|
||||||
|
plan.description = "Test description";
|
||||||
|
plan.subTasks = {
|
||||||
|
{"X", "P006", "Task X", "Description X", 0, ""},
|
||||||
|
{"Y", "P006", "Task Y", "Description Y", 1, ""}
|
||||||
|
};
|
||||||
|
plan.score = 0.0;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "core/event.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace battlefield {
|
||||||
|
|
||||||
|
class EventProcessorTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp() override {
|
||||||
|
processor_ = std::make_unique<EventProcessor>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
processor_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<EventProcessor> 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
|
||||||
Loading…
Reference in New Issue