task_auto_execute_plan/tests/basic_test.cpp

360 lines
13 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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 <cassert>
#include <cstring>
#include <iostream>
// 辅助:构造合法事件
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<const uint8_t*>(&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<const uint8_t*>(&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;
}