/** * @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 #include #include #include #include #include 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 = "空情预警"; 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 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 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 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 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; }