/** * @file basic_test.cpp * @brief FZKJ 核心软件基础单元测试(使用标准库 assert) * * 测试覆盖: * - SRS-FZKJ_F-001 事件处理与任务生成 * - SRS-FZKJ_F-002 方案管理与对比 * - SRS-FZKJ_F-003 方案分发与状态监控 * - SRS-FZKJ_F-004 地图量算 * - SRS-FZKJ_F-005 数据中转与存储 * - SRS-FZKJ_F-006 系统配置与模式切换 * - 数据结构正确性验证 */ #include "app.hpp" #include #include #include // 辅助:构造合法事件 static fzkj::EventPayload MakeValidEvent(uint8_t type, uint32_t source_id) { fzkj::EventPayload evt; std::memset(&evt, 0, sizeof(evt)); evt.event_type = type; evt.timestamp_ms = 1680000000000ULL; evt.source_id = source_id; // 计算校验码(异或) const uint8_t* raw = reinterpret_cast(&evt); uint8_t cs = 0; for (std::size_t i = 0; i < sizeof(fzkj::EventPayload) - 1; ++i) { cs ^= raw[i]; } evt.checksum = cs; return evt; } // ============================================================ // 测试用例:数据结构 // ============================================================ static void TestDataStructures() { std::cout << "[Test] 数据结构验证...\n"; // EventPayload 定长 256 字节 fzkj::EventPayload evt; std::memset(&evt, 0, sizeof(evt)); assert(sizeof(evt) == fzkj::kEventPayloadSize); std::cout << " ✓ EventPayload 大小为 " << sizeof(evt) << " 字节 (预期 256)\n"; // Task 默认构造 fzkj::Task task; assert(task.task_id == 0); task.task_id = 42; task.description = "测试任务"; std::string str = task.ToString(); assert(str.find("42") != std::string::npos); assert(str.find("测试任务") != std::string::npos); std::cout << " ✓ Task::ToString() 正确: " << str << "\n"; // BattleSolution fzkj::BattleSolution sol{1, 1, "方案A", "测试", 95.0, false}; assert(sol.solution_id == 1); assert(sol.score == 95.0); std::cout << " ✓ BattleSolution 构造正确\n"; // ExecutionUnit fzkj::ExecutionUnit unit{100, "测试单元", fzkj::ExecutionStatus::kPending}; assert(unit.unit_id == 100); assert(unit.status == fzkj::ExecutionStatus::kPending); std::cout << " ✓ ExecutionUnit 构造正确\n"; // GeoPoint fzkj::GeoPoint pt{39.9, 116.4, 0.0}; assert(pt.latitude == 39.9); assert(pt.longitude == 116.4); std::cout << " ✓ GeoPoint 构造正确\n"; // SystemConfig fzkj::SystemConfig cfg; std::string cfg_str = cfg.ToString(); assert(cfg_str.find("默认想定") != std::string::npos); std::cout << " ✓ SystemConfig 正确: " << cfg_str << "\n"; std::cout << " ✓ 所有数据结构验证通过\n\n"; } // ============================================================ // 测试用例:SRS-FZKJ_F-001 事件处理 // ============================================================ static void TestEventProcessing() { std::cout << "[Test] SRS-FZKJ_F-001 事件处理...\n"; fzkj::App app; // 1. 接收到合法事件后应生成任务 auto evt1 = MakeValidEvent(1, 1001); auto ret = app.ReceiveEvent(evt1); assert(ret == fzkj::EventProcessResult::kTaskGenerated); std::cout << " ✓ 合法事件处理成功,生成任务\n"; // 2. 冗余事件应被过滤 auto evt2 = MakeValidEvent(1, 1001); evt2.timestamp_ms = evt1.timestamp_ms; // 同一事件 evt2.source_id = evt1.source_id; evt2.event_type = evt1.event_type; // 重算校验码以匹配 const uint8_t* raw2 = reinterpret_cast(&evt2); uint8_t cs2 = 0; for (std::size_t i = 0; i < sizeof(fzkj::EventPayload) - 1; ++i) { cs2 ^= raw2[i]; } evt2.checksum = cs2; ret = app.ReceiveEvent(evt2); assert(ret == fzkj::EventProcessResult::kValidationFailed); std::cout << " ✓ 冗余事件被正确过滤\n"; // 3. 无效校验码事件应被拒绝 fzkj::EventPayload bad_evt; std::memset(&bad_evt, 0, sizeof(bad_evt)); bad_evt.event_type = 2; bad_evt.checksum = 0xFF; // 错误的校验码 ret = app.ReceiveEvent(bad_evt); assert(ret == fzkj::EventProcessResult::kValidationFailed); std::cout << " ✓ 无效校验码事件被拒绝\n"; std::cout << " ✓ 事件处理测试通过\n\n"; } // ============================================================ // 测试用例:SRS-FZKJ_F-002 方案管理 // ============================================================ static void TestSolutionManagement() { std::cout << "[Test] SRS-FZKJ_F-002 方案管理...\n"; fzkj::App app; // 添加方案 fzkj::BattleSolution s1{1, 1, "方案甲", "集中突防", 90.0, false}; fzkj::BattleSolution s2{2, 1, "方案乙", "分布式突防", 85.0, true}; assert(app.AddSolution(s1)); assert(app.AddSolution(s2)); std::cout << " ✓ 添加 2 个方案成功\n"; auto solutions = app.GetSolutions(); assert(solutions.size() == 2); std::cout << " ✓ 获取方案列表,size=" << solutions.size() << "\n"; // 按评分排序 app.SortByPreference("score"); solutions = app.GetSolutions(); assert(solutions[0].score >= solutions[1].score); std::cout << " ✓ 按评分排序正确\n"; // 对比方案 auto cmp = app.CompareSolutions(1, 2); assert(cmp.solution_a_id == 1); assert(cmp.solution_b_id == 2); std::cout << " ✓ 方案对比结果: " << cmp.summary << "\n"; std::cout << " ✓ 方案管理测试通过\n\n"; } // ============================================================ // 测试用例:SRS-FZKJ_F-003 方案分发与状态监控 // ============================================================ static void TestPlanDispatch() { std::cout << "[Test] SRS-FZKJ_F-003 方案驱动与状态监控...\n"; fzkj::App app; fzkj::BattleSolution s{10, 1, "突防方案", "测试", 90.0, false}; app.AddSolution(s); // 分发方案 bool ok = app.DispatchPlan(10); assert(ok); std::cout << " ✓ 方案分发成功\n"; // 监控状态 auto status = app.MonitorExecutionStatus(1); assert(status == fzkj::ExecutionStatus::kInProgress); std::cout << " ✓ 执行单元状态为执行中\n"; // 触发异常 ok = app.TriggerAlertOnFailure(1); assert(ok); status = app.MonitorExecutionStatus(1); assert(status == fzkj::ExecutionStatus::kFailed); std::cout << " ✓ 异常告警触发成功,状态变更为失败\n"; // 不存在的方案 ok = app.DispatchPlan(999); assert(!ok); std::cout << " ✓ 不存在的方案分发返回 false\n"; std::cout << " ✓ 方案分发与监控测试通过\n\n"; } // ============================================================ // 测试用例:SRS-FZKJ_F-004 地图与量算 // ============================================================ static void TestMapAndMeasure() { std::cout << "[Test] SRS-FZKJ_F-004 共用态势与地图...\n"; fzkj::App app; // 加载地图 bool ok = app.LoadGisMap("test_map.tif"); assert(ok); std::cout << " ✓ GIS 地图加载成功\n"; // 叠加图层 fzkj::SituationLayer layer{"雷达图层", true}; ok = app.OverlaySituationLayer(layer); assert(ok); std::cout << " ✓ 态势图层叠加成功\n"; // 量算距离(北京→上海约 1068 km) fzkj::GeoPoint beijing{39.9042, 116.4074, 0.0}; fzkj::GeoPoint shanghai{31.2304, 121.4737, 0.0}; auto measure = app.MeasureDistance(beijing, shanghai); // 预期在 1000~1200 km 之间 assert(measure.distance_m > 900000.0); assert(measure.distance_m < 1300000.0); std::cout << " ✓ 北京→上海距离量算: " << (measure.distance_m / 1000.0) << " km (预期约 1068 km)\n"; // 切换网格 app.ToggleGridDisplay(); std::cout << " ✓ 网格显示切换成功\n"; std::cout << " ✓ 地图与态势测试通过\n\n"; } // ============================================================ // 测试用例:SRS-FZKJ_F-005 数据中转与存储 // ============================================================ static void TestDataTransfer() { std::cout << "[Test] SRS-FZKJ_F-005 数据中转与存储...\n"; fzkj::App app; uint8_t data[] = {10, 20, 30, 40}; bool ok = app.ForwardDataToModule("测试模块", data, sizeof(data)); assert(ok); std::cout << " ✓ 数据转发成功\n"; ok = app.PersistCacheToDb(); assert(ok); std::cout << " ✓ 缓存持久化成功\n"; ok = app.ClearScenarioCache(); assert(ok); std::cout << " ✓ 想定缓存清空成功\n"; // 空数据应返回 false ok = app.ForwardDataToModule("测试模块", nullptr, 10); assert(!ok); std::cout << " ✓ 空数据转发返回 false\n"; std::cout << " ✓ 数据中转测试通过\n\n"; } // ============================================================ // 测试用例:SRS-FZKJ_F-006 系统设置与模式切换 // ============================================================ static void TestSystemConfig() { std::cout << "[Test] SRS-FZKJ_F-006 系统设置与模式切换...\n"; fzkj::App app; // 初始为正常模式 assert(app.GetCurrentMode() == fzkj::WorkMode::kNormal); std::cout << " ✓ 初始模式为正常模式\n"; // 切换到降级模式 bool ok = app.SwitchExecutionMode(fzkj::WorkMode::kDegraded); assert(ok); assert(app.GetCurrentMode() == fzkj::WorkMode::kDegraded); std::cout << " ✓ 切换到降级模式成功\n"; // 降级模式不能直接进入配置维护 ok = app.SwitchExecutionMode(fzkj::WorkMode::kConfigMaintain); assert(!ok); std::cout << " ✓ 降级→维护 转换被拒绝(符合状态图)\n"; // 降级→正常 ok = app.SwitchExecutionMode(fzkj::WorkMode::kNormal); assert(ok); std::cout << " ✓ 降级→正常 切换成功\n"; // 正常→配置维护 ok = app.SwitchExecutionMode(fzkj::WorkMode::kConfigMaintain); assert(ok); std::cout << " ✓ 正常→配置维护 切换成功\n"; // 配置维护只能回正常 ok = app.SwitchExecutionMode(fzkj::WorkMode::kDegraded); assert(!ok); std::cout << " ✓ 维护→降级 被拒绝\n"; ok = app.SwitchExecutionMode(fzkj::WorkMode::kNormal); assert(ok); std::cout << " ✓ 维护→正常 切换成功\n"; // 更新算法配置 app.SetAlgorithmConfig("强化学习算法", 0.8); auto& cfg = app.GetConfig(); assert(cfg.algorithm_name == "强化学习算法"); assert(cfg.algorithm_param == 0.8); std::cout << " ✓ 算法配置更新成功\n"; // 加载想定 ok = app.LoadScenarioParams("红蓝对抗想定-2025"); assert(ok); assert(cfg.scenario_name == "红蓝对抗想定-2025"); std::cout << " ✓ 想定加载成功\n"; // 网络配置 ok = app.ApplyNetworkConfiguration("10.0.0.1", 8888); assert(ok); assert(cfg.ip_address == "10.0.0.1"); assert(cfg.port == 8888); std::cout << " ✓ 网络配置更新成功\n"; std::cout << " ✓ 系统配置测试通过\n\n"; } // ============================================================ // 测试用例:系统自检 // ============================================================ static void TestSelfCheck() { std::cout << "[Test] 系统自检...\n"; fzkj::App app; assert(app.SelfTest()); std::cout << " ✓ 系统自检通过\n\n"; } // ============================================================ // 主测试入口 // ============================================================ int main() { std::cout << "\n╔══════════════════════════════════════════╗\n"; std::cout << "║ FZKJ 核心软件 - 基础单元测试套件 ║\n"; std::cout << "║ 版本 1.6.0 标准库 assert ║\n"; std::cout << "╚══════════════════════════════════════════╝\n\n"; TestDataStructures(); TestEventProcessing(); TestSolutionManagement(); TestPlanDispatch(); TestMapAndMeasure(); TestDataTransfer(); TestSystemConfig(); TestSelfCheck(); std::cout << "╔══════════════════════════════════════════╗\n"; std::cout << "║ 全部测试通过! ✓ ║\n"; std::cout << "╚══════════════════════════════════════════╝\n"; return 0; }