task_plan_execute/tests/basic_test.cpp

392 lines
14 KiB
C++
Raw Permalink Normal View History

2026-06-09 05:14:15 +00:00
/**
* @file basic_test.cpp
* @brief
*
* 使 assert
* - SU-01:
* - SU-02:
* - SU-03:
* - SU-04:
* - SU-05:
* - SU-06:
* - SU-07:
* - SU-08:
*/
#include "app.hpp"
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <chrono>
using namespace bmp;
/**
* @brief SU-01
*
* @requirement(name="事件接收与处理", id="SU-01")
* JSON事件XML事件
*/
static void testEventReception() {
std::cout << "[测试] SU-01: 事件接收与处理" << std::endl;
EventService svc;
// 测试1: 接收有效JSON事件
std::string jsonEvent = "{ \"type\": \"敌情侦察\", \"priority\": \"HIGH\" }";
bool result = svc.receiveEvent(jsonEvent);
assert(result && "接收有效JSON事件应该成功");
// 测试2: 接收有效XML事件
std::string xmlEvent = "<event><type>空情预警</type></event>";
result = svc.receiveEvent(xmlEvent);
assert(result && "接收有效XML事件应该成功");
// 测试3: 接收空数据
result = svc.receiveEvent("");
assert(!result && "接收空数据应该失败");
// 测试4: 接收无效数据既不是JSON也不是XML
result = svc.receiveEvent("invalid data without brackets");
assert(!result && "接收无效格式数据应该失败");
// 测试5: 发送ACK
std::string ack = svc.sendAck("unknown");
assert(ack == "ACK:UNKNOWN" && "未知事件ID应返回 UNKNOWN");
std::cout << " SU-01 测试通过!" << std::endl << std::endl;
}
/**
* @brief SU-02
*
* @requirement(name="事件标准化处理", id="SU-02")
*
*/
static void testEventStandardization() {
std::cout << "[测试] SU-02: 事件标准化处理" << std::endl;
EventService svc;
// 准备测试数据
std::string jsonEvent = "{ \"type\": \"敌情侦察\", \"priority\": \"HIGH\" }";
svc.receiveEvent(jsonEvent);
auto pending = svc.getPendingEvents();
assert(!pending.empty() && "应有待处理事件");
// 测试1: 获取原始事件
const Event* raw = svc.getRawEvent(pending[0].id);
assert(raw != nullptr && "应能获取原始事件");
assert(raw->status == EventStatus::PENDING && "原始事件状态应为PENDING");
// 测试2: 处理事件(标准化)
bool processed = svc.processEvent(pending[0].id);
assert(processed && "事件标准化应成功");
// 测试3: 再次处理应失败(状态已变更)
processed = svc.processEvent(pending[0].id);
assert(!processed && "重复处理应失败");
// 测试4: 处理不存在的事件
processed = svc.processEvent("nonexistent");
assert(!processed && "处理不存在的事件应失败");
// 测试5: 保存标准化事件
Event customEvent;
customEvent.id = "CUSTOM_001";
customEvent.title = "测试事件";
customEvent.status = EventStatus::ACCEPTED;
svc.saveStandardEvent(customEvent);
const Event* saved = svc.getRawEvent("CUSTOM_001");
assert(saved != nullptr && "保存后应能获取标准化事件");
assert(saved->status == EventStatus::ACCEPTED && "标准化事件状态应正确");
std::cout << " SU-02 测试通过!" << std::endl << std::endl;
}
/**
* @brief SU-03
*
* @requirement(name="事件展示与操作", id="SU-03")
*
*/
static void testEventQuery() {
std::cout << "[测试] SU-03: 事件展示与操作" << std::endl;
EventService svc;
// 准备测试数据
svc.receiveEvent("{ \"type\": \"A\" }");
svc.receiveEvent("{ \"type\": \"B\" }");
// 测试1: 查询所有事件
auto all = svc.queryEvents({});
assert(all.size() == 2 && "应有2个事件");
// 测试2: 获取待处理事件
auto pending = svc.getPendingEvents();
assert(pending.size() == 2 && "应有2个待处理事件");
// 测试3: 过滤状态
auto filtered = svc.queryEvents({{"status", "PENDING"}});
assert(filtered.size() == 2 && "过滤PENDING应有2个");
std::cout << " SU-03 测试通过!" << std::endl << std::endl;
}
/**
* @brief SU-05
*
* @requirement(name="任务模板管理", id="SU-05")
*
*/
static void testTemplateManagement() {
std::cout << "[测试] SU-05: 任务模板管理" << std::endl;
TemplateService svc;
// 测试1: 接收空数据
size_t count = svc.receiveTemplates("");
assert(count == 0 && "空数据应解析出0个模板");
// 测试2: 接收有效模板
std::string tmplData =
"{\"id\":\"T1\",\"name\":\"模板1\",\"scenario\":\"侦察\"}\n"
"{\"id\":\"T2\",\"name\":\"模板2\",\"scenario\":\"预警\"}\n";
count = svc.receiveTemplates(tmplData);
assert(count == 2 && "应有2个模板被解析");
// 测试3: 获取模板列表
auto list = svc.getTemplateList();
assert(list.size() == 2 && "模板列表应有2个");
// 测试4: 选择模板
bool selected = svc.selectTemplate("T1");
assert(selected && "选择存在的模板应成功");
selected = svc.selectTemplate("NONEXIST");
assert(!selected && "选择不存在的模板应失败");
// 测试5: 推荐模板
std::string recommended = svc.recommendTemplate("侦察");
assert(recommended == "T1" && "应为侦察推荐T1模板");
recommended = svc.recommendTemplate("未知");
assert(!recommended.empty() && "无匹配时应有默认推荐");
// 测试6: 获取配置
auto config = svc.getConfig();
assert(config.find("auto_recommend") != config.end() && "应有auto_recommend配置");
std::cout << " SU-05 测试通过!" << std::endl << std::endl;
}
/**
* @brief SU-04, SU-06
*
* @requirement(name="任务生成", id="SU-04")
* @requirement(name="计划管理", id="SU-06")
* HITL通知
*/
static void testPlanManagement() {
std::cout << "[测试] SU-04/SU-06: 任务生成与计划管理" << std::endl;
PlanService svc;
// 测试1: 生成任务 - 空参数应失败
std::string planId = svc.generateTask("", "T1", {});
assert(planId.empty() && "空事件ID应生成失败");
// 测试2: 生成任务 - 有效参数
planId = svc.generateTask("EVT_001", "T1", {{"remarks", "测试"}});
assert(!planId.empty() && "有效参数应生成计划");
assert(planId.find("PLAN_") == 0 && "计划ID应以PLAN_开头");
// 测试3: 提交任务
TaskPlan plan = svc.submitTask(planId);
assert(plan.status == PlanStatus::CONFIRMED && "提交后状态应为CONFIRMED");
assert(plan.id == planId && "返回的计划ID应匹配");
// 测试4: 提交不存在的计划
TaskPlan emptyPlan = svc.submitTask("NONEXIST");
assert(emptyPlan.id.empty() && "不存在的计划应返回空");
// 测试5: 获取计划列表
auto plans = svc.getPlanList();
assert(plans.size() == 1 && "应有1个计划");
// 测试6: 排序计划
svc.sortPlans({{"priority", 1}, {"time", 1}});
// 测试7: 计划重配置
std::vector<PlanNode> newNodes;
PlanNode node;
node.nodeId = "NODE_001";
node.planId = planId;
node.taskType = "侦察";
node.executeUnit = "无人机";
newNodes.push_back(node);
bool reconfigured = svc.reconfigurePlan(planId, newNodes);
assert(reconfigured && "重配置应成功");
// 重配置不存在的计划
reconfigured = svc.reconfigurePlan("NONEXIST", newNodes);
assert(!reconfigured && "重配置不存在计划应失败");
// 测试8: HITL通知
svc.notifyHITL(planId, "请确认方案");
svc.notifyHITL("NONEXIST", "测试"); // 不应崩溃
std::cout << " SU-04/SU-06 测试通过!" << std::endl << std::endl;
}
/**
* @brief SU-07
*
* @requirement(name="方案分发", id="SU-07")
* ACK接收
*/
static void testDistribution() {
std::cout << "[测试] SU-07: 方案分发" << std::endl;
DistributionService svc;
// 测试1: 分发计划
auto logs = svc.distributePlan("PLAN_001");
assert(logs.size() == 3 && "应有3条分发日志");
for (const auto& log : logs) {
assert(!log.logId.empty() && "日志ID不应为空");
assert(log.response == DistributionResponse::TIMEOUT && "初始状态应为TIMEOUT");
assert(log.retryCount == 0 && "初始重试次数应为0");
}
// 测试2: 接收ACK
bool ackOk = svc.receiveAck(logs[0].logId, DistributionResponse::ACK);
assert(ackOk && "接收ACK应成功");
ackOk = svc.receiveAck("NONEXIST", DistributionResponse::ACK);
assert(!ackOk && "接收不存在的日志ACK应失败");
// 测试3: 接收NACK并验证重试
bool nackOk = svc.receiveAck(logs[1].logId, DistributionResponse::NACK);
assert(nackOk && "接收NACK应成功");
// 测试4: 查询分发日志
auto queriedLogs = svc.getLogsByPlan("PLAN_001");
assert(queriedLogs.size() == 3 && "应有3条日志");
assert(queriedLogs[0].response == DistributionResponse::ACK && "第一条应为ACK");
assert(queriedLogs[1].response == DistributionResponse::NACK && "第二条应为NACK");
// 测试5: 状态更新(不崩溃即可)
svc.updateStatus("PLAN_001");
std::cout << " SU-07 测试通过!" << std::endl << std::endl;
}
/**
* @brief SU-08
*
* @requirement(name="状态监控", id="SU-08")
*
*/
static void testStatusMonitoring() {
std::cout << "[测试] SU-08: 状态监控" << std::endl;
StatusMonitorService svc;
// 测试1: 接收有效遥测数据
std::vector<uint8_t> validData = {
0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x28,
0x4E, 0x6F, 0x72, 0x6D, 0x61, 0x6C
};
StatusLog log = svc.receiveTelemetry(validData);
assert(!log.recordId.empty() && "记录ID不应为空");
assert(!log.isAbnormal && "正常状态码不应标记为异常");
// 测试2: 接收异常遥测数据
std::vector<uint8_t> abnormalData = {
0x00, 0x01, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x23, 0x38, // 9016 > 9000
0x45, 0x72, 0x72, 0x6F, 0x72
};
StatusLog abnormalLog = svc.receiveTelemetry(abnormalData);
assert(abnormalLog.isAbnormal && "状态码大于9000应标记为异常");
// 测试3: 接收短数据(无效)
std::vector<uint8_t> shortData = {0x00, 0x01};
StatusLog shortLog = svc.receiveTelemetry(shortData);
assert(shortLog.isAbnormal && "短数据应标记为异常");
assert(shortLog.statusCode == "ERR_INVALID_DATA" && "短数据应有错误码");
// 测试4: 触发报警
std::string alarm = svc.triggerAlarm(abnormalLog);
assert(!alarm.empty() && "异常状态应触发报警");
assert(alarm.find("[ALARM]") == 0 && "报警消息应以[ALARM]开头");
// 正常状态不触发报警
alarm = svc.triggerAlarm(log);
assert(alarm.empty() && "正常状态不应触发报警");
// 测试5: 获取最新状态
StatusLog latest = svc.getLatestStatus("AST_65537");
assert(latest.assetId == "AST_65537" && "应返回正确资产的状态");
// 不存在的资产
latest = svc.getLatestStatus("UNKNOWN");
assert(latest.isAbnormal && "不存在的资产应标记异常");
// 测试6: 数据陈旧检查
std::this_thread::sleep_for(std::chrono::milliseconds(50));
svc.checkStaleData(10);
StatusLog staleLog = svc.getLatestStatus("AST_65537");
assert(staleLog.isAbnormal && "超过阈值后应标记为陈旧");
assert(staleLog.statusCode == "STALE" && "陈旧数据状态码应为STALE");
std::cout << " SU-08 测试通过!" << std::endl << std::endl;
}
/**
* @brief
*
* @requirement(name="业务目标", id="REQ-BMP-001")
*
*/
static void testSystemIntegration() {
std::cout << "[测试] BMP集成: 系统外观类" << std::endl;
BattlefieldMissionPlanner bmp;
// 测试1: 初始化
bool initialized = bmp.initialize();
assert(initialized && "系统初始化应成功");
// 测试2: 获取各服务引用
assert(&bmp.getEventService() != nullptr && "事件服务不应为空");
assert(&bmp.getTemplateService() != nullptr && "模板服务不应为空");
assert(&bmp.getPlanService() != nullptr && "计划服务不应为空");
assert(&bmp.getDistributionService() != nullptr && "分发服务不应为空");
assert(&bmp.getStatusMonitorService() != nullptr && "状态监控服务不应为空");
// 测试3: 运行主循环(不崩溃即可)
bmp.run();
std::cout << " BMP集成测试通过" << std::endl << std::endl;
}
int main() {
std::cout << "========================================" << std::endl;
std::cout << " 战场任务规划管理系统 - 单元测试" << std::endl;
std::cout << "========================================" << std::endl << std::endl;
testEventReception();
testEventStandardization();
testEventQuery();
testTemplateManagement();
testPlanManagement();
testDistribution();
testStatusMonitoring();
testSystemIntegration();
std::cout << "========================================" << std::endl;
std::cout << " 全部测试通过!" << std::endl;
std::cout << "========================================" << std::endl;
return 0;
}