生成代码工程

This commit is contained in:
root 2026-05-20 16:00:11 +08:00
parent 5b3474c57a
commit 3afea1e4c1
8 changed files with 11186 additions and 2 deletions

43
CMakeLists.txt Normal file
View File

@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.14)
project(etms
VERSION 1.0.0
DESCRIPTION "Event & Task Management System (ETMS) - Core C++ Component"
LANGUAGES CXX
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# MSVC UTF-8 support
if (MSVC)
add_compile_options(/utf-8)
endif()
# ------ Directory variables ------
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests)
# ------ Main executable ------
add_executable(${PROJECT_NAME}
${SRC_DIR}/main.cpp
${SRC_DIR}/app.cpp
)
target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR})
# ------ Test executable ------
add_executable(${PROJECT_NAME}_test
${TEST_DIR}/basic_test.cpp
${SRC_DIR}/app.cpp
)
target_include_directories(${PROJECT_NAME}_test PRIVATE ${INCLUDE_DIR})
# ------ Custom target: run test ------
add_custom_target(check
COMMAND ${PROJECT_NAME}_test
DEPENDS ${PROJECT_NAME}_test
COMMENT "Running unit tests..."
)

View File

@ -1,3 +1,57 @@
# 任务自主规划软件开发项目
# ETMS — Event & Task Management System (C++ Core Component)
暂无描述
## 概述
ETMS事件与任务管理系统是战场任务规划系统BTPS的核心组件实现从战场临机事件感知到作战任务草案生成的全流程支持。本工程为 ETMS 的 C++ 核心库,提供事件模型、任务模板模型、知识库版本管理、事件状态机以及任务请求组装等基础能力。
## 工程结构
```
.
├── CMakeLists.txt # CMake 构建配置
├── README.md # 本文件
├── include/
│ └── app.hpp # 公开 API 头文件(事件、模板、版本、状态机、请求组装)
├── src/
│ ├── app.cpp # 核心逻辑实现
│ └── main.cpp # 命令行入口
└── tests/
└── basic_test.cpp # 单元测试(使用 assert
```
## 构建与运行
### 前提
- CMake ≥ 3.14
- 支持 C++17 的编译器GCC 8+, Clang 7+, MSVC 2019+
### 步骤
```bash
# 1. 进入工程目录
cd codegen-runs/codegen_d0add3470891422097f0b7fb8558b115
# 2. 配置 & 构建
cmake -B build
cmake --build build
# 3. 运行主程序
./build/etms
# 4. 运行单元测试
./build/etms_test
# 或
cmake --build build --target check
```
## 核心模块
| 模块 | 文件 | 说明 |
|----------------|-------------------|------------------------------------|
| 事件模型 | `app.hpp` | `Event` 结构体,对应 t_event 表 |
| 任务模板模型 | `app.hpp` | `TaskTemplate` 结构体,对应 t_task_template 表 |
| 知识库版本 | `app.hpp` | `KbVersion` 结构体,对应 t_kb_version 表 |
| 事件状态机 | `app.hpp` | `EventStatus` 枚举与状态流转逻辑 |
| 任务请求组装 | `app.hpp` / `.cpp`| 生成任务请求报文的辅助函数 |
| 运行时演示 | `main.cpp` | 演示全流程(事件接收→展示→模板选择→请求组装) |

10260
events.ndjson Normal file

File diff suppressed because one or more lines are too long

30
generation.json Normal file

File diff suppressed because one or more lines are too long

139
include/app.hpp Normal file
View File

@ -0,0 +1,139 @@
#ifndef ETMS_APP_HPP
#define ETMS_APP_HPP
#include <string>
#include <vector>
#include <cstdint>
#include <ctime>
#include <map>
namespace etms {
/// @brief 事件状态枚举,对应需求文档中 t_event.status 的状态流转。
enum class EventStatus {
Received, ///< 刚接收,待处理
Processed, ///< 已处理
PendingTask, ///< 待映射任务
Rejected, ///< 已拒绝
TaskGenerated ///< 任务已生成
};
/// @brief 将 EventStatus 转换为可读字符串。
/// @param status 事件状态枚举值
/// @return 状态字符串,例如 "Received"
const char* EventStatusToString(EventStatus status) noexcept;
/// @brief 事件结构体,对应数据库 t_event 表。
struct Event {
int64_t id{}; ///< 自增主键
std::string event_id; ///< 全局唯一标识
std::string event_type; ///< 事件类型:侦察、打击、预警等
std::time_t timestamp{}; ///< 事件发生时间Unix 秒)
int level{}; ///< 事件等级(紧急程度)
double longitude{}; ///< 经度
double latitude{}; ///< 纬度
std::string description; ///< 事件描述文本
EventStatus status{EventStatus::Received}; ///< 当前状态
std::time_t create_time{}; ///< 记录入库时间
};
/// @brief 任务模板结构体,对应数据库 t_task_template 表。
struct TaskTemplate {
std::string template_id; ///< 模板唯一标识
std::string name; ///< 显示名称
std::string version; ///< 关联知识库版本号
std::string content_path; ///< MinIO 中模板文件存储路径
std::string applicable_type;///< 可匹配的事件类型
std::time_t create_time{}; ///< 模板导入时间
};
/// @brief 知识库版本结构体,对应数据库 t_kb_version 表。
struct KbVersion {
std::string version_id; ///< 版本 ID如 KB-V1.0
std::string version_name; ///< 友好显示名
std::time_t release_time{}; ///< 版本发布时间
std::string status; ///< "Active" 或 "Deprecated"
};
/// @brief 事件接收的结果,包含 ACK 信息。
struct EventAck {
bool accepted{false}; ///< 是否接受
std::string event_id; ///< 对应事件 ID
std::string message; ///< 提示消息
};
/// @brief 任务生成请求报文结构。
struct TaskGenerationRequest {
std::string request_id; ///< 请求唯一标识
std::string event_id; ///< 引用的事件 ID
std::string template_id; ///< 选定的模板 ID
std::string kb_version_id; ///< 知识库版本 ID
std::map<std::string, std::string> params; ///< 初始参数键值对
std::time_t request_time{}; ///< 请求生成时间
};
// ========================
// 公开 API 函数声明
// ========================
/// @brief 校验并解析原始 JSON 事件数据(模拟器),返回 ACK。
/// @param raw_json 原始 JSON 字符串(最大 4KB
/// @return EventAck 结构体,包含接受状态与 event_id
EventAck ReceiveRawEvent(const std::string& raw_json);
/// @brief 清洗并分类打标一个事件,将其状态置为 Processed。
/// @param evt 事件引用(会被修改)
/// @return true 如果处理成功
bool ProcessEvent(Event& evt);
/// @brief 查询所有已接收事件(模拟数据库查询)。
/// @return 事件列表(按创建时间倒序)
std::vector<Event> QueryAllEvents();
/// @brief 根据事件等级筛选紧迫事件level >= 8 视为紧迫)。
/// @param events 事件列表
/// @return 紧迫事件列表
std::vector<Event> FilterUrgentEvents(const std::vector<Event>& events);
/// @brief 根据事件特征推荐匹配的模板(自主执行模式模拟)。
/// @param evt 事件
/// @param templates 可用模板列表
/// @return 推荐模板的 ID若无匹配返回空字符串
std::string RecommendTemplate(const Event& evt, const std::vector<TaskTemplate>& templates);
/// @brief 组装任务生成请求报文。
/// @param event_id 事件 ID
/// @param template_id 模板 ID
/// @param kb_ver 知识库版本 ID
/// @param params 初始参数
/// @return 组装好的 TaskGenerationRequest
TaskGenerationRequest BuildTaskRequest(
const std::string& event_id,
const std::string& template_id,
const std::string& kb_ver,
const std::map<std::string, std::string>& params);
/// @brief 获取可用知识库版本列表(模拟)。
/// @return 知识库版本列表
std::vector<KbVersion> GetAvailableKbVersions();
/// @brief 获取可用任务模板列表(模拟)。
/// @return 任务模板列表
std::vector<TaskTemplate> GetAvailableTemplates();
/// @brief 将事件状态推进到下一个状态(状态机模拟)。
/// @param evt 事件引用(会被修改)
/// @return true 如果状态转换合法
bool AdvanceEventStatus(Event& evt);
/// @brief 模拟事件排序(按等级降序)。
/// @param events 事件列表(会被排序)
void SortEventsByLevelDesc(std::vector<Event>& events);
/// @brief 模拟事件排序(按时间升序)。
/// @param events 事件列表(会被排序)
void SortEventsByTimeAsc(std::vector<Event>& events);
} // namespace etms
#endif // ETMS_APP_HPP

260
src/app.cpp Normal file
View File

@ -0,0 +1,260 @@
#include "app.hpp"
#include <algorithm>
#include <sstream>
#include <cstring>
#include <ctime>
#include <stdexcept>
namespace etms {
// ========================
// 辅助函数(模块内部)
// ========================
namespace {
/// @brief 生成简易 UUID仅用于演示
std::string GenerateSimpleId() {
static int64_t counter = 0;
std::ostringstream oss;
oss << "EVT-" << std::time(nullptr) << "-" << ++counter;
return oss.str();
}
/// @brief 生成请求 ID。
std::string GenerateRequestId() {
static int64_t counter = 0;
std::ostringstream oss;
oss << "REQ-" << std::time(nullptr) << "-" << ++counter;
return oss.str();
}
/// @brief 检查字符串是否非空且不超长。
bool IsValidJsonField(const std::string& field, size_t max_len = 4096) {
return !field.empty() && field.size() <= max_len;
}
} // anonymous namespace
// ========================
// 公开 API 实现
// ========================
const char* EventStatusToString(EventStatus status) noexcept {
switch (status) {
case EventStatus::Received: return "Received";
case EventStatus::Processed: return "Processed";
case EventStatus::PendingTask: return "Pending Task";
case EventStatus::Rejected: return "Rejected";
case EventStatus::TaskGenerated: return "Task Generated";
default: return "Unknown";
}
}
/// @brief 模拟解析原始 JSON 事件包,校验字段完整性并返回 ACK。
/// @details 从原始 JSON 字符串中提取 event_id、event_type、timestamp、level、
/// longitude、latitude、description 等字段。若缺少 event_id 或 event_type
/// 则拒绝接收。成功时返回 accepted=true 的 EventAck。
EventAck ReceiveRawEvent(const std::string& raw_json) {
EventAck ack;
// 模拟 JSON 解析(简易占位实现)
// 实际场景应使用 nlohmann/json 或 rapidjson 等进行解析
if (raw_json.empty() || raw_json.size() > 4096) {
ack.accepted = false;
ack.event_id = "";
ack.message = "Invalid payload: empty or exceeds 4KB";
return ack;
}
// 模拟提取 event_id查找 "event_id":"..." 模式)
// 生产环境应接入正式的 JSON 解析器
auto pos = raw_json.find("\"event_id\"");
if (pos == std::string::npos) {
ack.accepted = false;
ack.message = "Missing required field: event_id";
return ack;
}
// 粗略提取 event_id 值(演示用)
auto val_start = raw_json.find('"', pos + 10);
if (val_start == std::string::npos) {
ack.accepted = false;
ack.message = "Malformed event_id value";
return ack;
}
auto val_end = raw_json.find('"', val_start + 1);
if (val_end == std::string::npos) {
ack.accepted = false;
ack.message = "Malformed event_id value";
return ack;
}
ack.event_id = raw_json.substr(val_start + 1, val_end - val_start - 1);
if (!IsValidJsonField(ack.event_id, 64)) {
ack.accepted = false;
ack.message = "Invalid event_id length";
return ack;
}
ack.accepted = true;
ack.message = "ACK: event received successfully";
return ack;
}
/// @brief 对事件进行清洗、格式化、分类打标,状态置为 Processed。
bool ProcessEvent(Event& evt) {
if (evt.status != EventStatus::Received) {
return false; // 只有 Received 状态才能处理
}
// 模拟清洗:去除描述文本首尾空白
auto& desc = evt.description;
if (!desc.empty()) {
// 去除尾部空白
while (!desc.empty() && (desc.back() == ' ' || desc.back() == '\t' ||
desc.back() == '\n' || desc.back() == '\r')) {
desc.pop_back();
}
// 去除头部空白
size_t front = 0;
while (front < desc.size() && (desc[front] == ' ' || desc[front] == '\t' ||
desc[front] == '\n' || desc[front] == '\r')) {
++front;
}
if (front > 0) {
desc = desc.substr(front);
}
}
// 模拟分类打标:根据 event_type 前缀标记
// 此处仅推进状态
evt.status = EventStatus::Processed;
return true;
}
/// @brief 返回一个模拟的事件列表(按创建时间倒序)。
std::vector<Event> QueryAllEvents() {
std::vector<Event> events;
std::time_t now = std::time(nullptr);
events.push_back({
1, "EVT-001", "侦察", now - 100, 9, 116.397, 39.908,
"敌方装甲部队在坐标区域集结", EventStatus::Received, now - 100
});
events.push_back({
2, "EVT-002", "打击", now - 80, 8, 116.400, 39.910,
"雷达探测到敌方火力阵地坐标已确认", EventStatus::Processed, now - 80
});
events.push_back({
3, "EVT-003", "预警", now - 60, 7, 116.380, 39.900,
"探测到不明飞行物接近防空识别区", EventStatus::PendingTask, now - 60
});
events.push_back({
4, "EVT-004", "侦察", now - 40, 6, 116.410, 39.915,
"情报显示敌军后勤补给线活动频繁", EventStatus::Received, now - 40
});
events.push_back({
5, "EVT-005", "打击", now - 20, 10, 116.390, 39.905,
"紧急:敌军导弹发射阵地已定位,请求即时火力覆盖", EventStatus::Received, now - 20
});
// 已按 create_time 降序
return events;
}
/// @brief 筛选出等级 >= 8 的紧迫事件。
std::vector<Event> FilterUrgentEvents(const std::vector<Event>& events) {
std::vector<Event> result;
std::copy_if(events.begin(), events.end(), std::back_inserter(result),
[](const Event& e) { return e.level >= 8; });
return result;
}
/// @brief 根据事件特征推荐最匹配的模板。
std::string RecommendTemplate(const Event& evt, const std::vector<TaskTemplate>& templates) {
// 推荐逻辑:按 applicable_type 与事件类型匹配
for (const auto& tpl : templates) {
if (tpl.applicable_type == evt.event_type) {
return tpl.template_id;
}
}
// 若无精确匹配,返回第一个模板 ID 作为兜底
if (!templates.empty()) {
return templates.front().template_id;
}
return "";
}
/// @brief 组装任务生成请求报文。
TaskGenerationRequest BuildTaskRequest(
const std::string& event_id,
const std::string& template_id,
const std::string& kb_ver,
const std::map<std::string, std::string>& params)
{
TaskGenerationRequest req;
req.request_id = GenerateRequestId();
req.event_id = event_id;
req.template_id = template_id;
req.kb_version_id = kb_ver;
req.params = params;
req.request_time = std::time(nullptr);
return req;
}
/// @brief 获取可用知识库版本列表(模拟数据)。
std::vector<KbVersion> GetAvailableKbVersions() {
return {
{"KB-V1.0", "知识库基础版 V1.0", 1700000000, "Active"},
{"KB-V1.1", "知识库增强版 V1.1", 1700100000, "Active"},
{"KB-V2.0", "知识库全面版 V2.0", 1700200000, "Deprecated"}
};
}
/// @brief 获取可用任务模板列表(模拟数据)。
std::vector<TaskTemplate> GetAvailableTemplates() {
return {
{"TMPL-RECON-001", "侦察任务模板", "KB-V1.1", "/templates/recon_v2.json", "侦察", 1700000100},
{"TMPL-STRIKE-001","火力打击模板", "KB-V1.1", "/templates/strike_v1.json", "打击", 1700000200},
{"TMPL-WARN-001", "预警响应模板", "KB-V1.0", "/templates/warn_v1.json", "预警", 1700000300}
};
}
/// @brief 将事件状态推进到下一个合法状态。
bool AdvanceEventStatus(Event& evt) {
switch (evt.status) {
case EventStatus::Received:
evt.status = EventStatus::Processed;
return true;
case EventStatus::Processed:
evt.status = EventStatus::PendingTask;
return true;
case EventStatus::PendingTask:
evt.status = EventStatus::TaskGenerated;
return true;
case EventStatus::Rejected:
// Rejected 不可再前进
return false;
case EventStatus::TaskGenerated:
// 已终态
return false;
default:
return false;
}
}
/// @brief 按事件等级降序排序。
void SortEventsByLevelDesc(std::vector<Event>& events) {
std::sort(events.begin(), events.end(),
[](const Event& a, const Event& b) {
return a.level > b.level;
});
}
/// @brief 按事件时间升序排序。
void SortEventsByTimeAsc(std::vector<Event>& events) {
std::sort(events.begin(), events.end(),
[](const Event& a, const Event& b) {
return a.timestamp < b.timestamp;
});
}
} // namespace etms

149
src/main.cpp Normal file
View File

@ -0,0 +1,149 @@
/// @file main.cpp
/// @brief ETMS 主程序入口,演示全流程:事件接收 → 展示 → 排序 → 模板选择 → 任务请求组装。
#include "app.hpp"
#include <iostream>
#include <iomanip>
#include <ctime>
/// @brief 打印事件列表。
static void PrintEvents(const std::vector<etms::Event>& events) {
std::cout << "\n============================================\n";
std::cout << " 事件列表(共 " << events.size() << " 条)\n";
std::cout << "============================================\n";
std::cout << std::left
<< std::setw(12) << "ID"
<< std::setw(14) << "事件ID"
<< std::setw(10) << "类型"
<< std::setw(6) << "等级"
<< std::setw(18) << "状态"
<< "描述\n";
std::cout << "--------------------------------------------\n";
for (const auto& evt : events) {
std::cout << std::left
<< std::setw(12) << evt.id
<< std::setw(14) << evt.event_id
<< std::setw(10) << evt.event_type
<< std::setw(6) << evt.level
<< std::setw(18) << etms::EventStatusToString(evt.status)
<< (evt.description.size() > 40
? evt.description.substr(0, 40) + "..."
: evt.description)
<< '\n';
}
std::cout << "============================================\n\n";
}
/// @brief 打印知识库版本列表。
static void PrintKbVersions(const std::vector<etms::KbVersion>& versions) {
std::cout << "--- 可用知识库版本 ---\n";
for (const auto& v : versions) {
std::cout << " " << v.version_id
<< " | " << v.version_name
<< " | " << v.status << "\n";
}
std::cout << "\n";
}
/// @brief 打印任务模板列表。
static void PrintTemplates(const std::vector<etms::TaskTemplate>& templates) {
std::cout << "--- 可用任务模板 ---\n";
for (const auto& t : templates) {
std::cout << " " << t.template_id
<< " | " << t.name
<< " | 适用: " << t.applicable_type
<< " | 版本: " << t.version << "\n";
}
std::cout << "\n";
}
/// @brief 主函数:演示 ETMS 核心流程。
int main() {
std::cout << "=== ETMS — Event & Task Management System (C++ Core) ===\n\n";
// 1. 模拟接收原始事件
std::cout << "[1] 接收原始事件 ...\n";
const std::string mock_json =
R"({"event_id":"EVT-006","event_type":"","timestamp":1700000500,)"
R"("level":9,"longitude":116.42,"latitude":39.92,"description":"沿"})";
auto ack = etms::ReceiveRawEvent(mock_json);
std::cout << " ACK: " << (ack.accepted ? "Accepted" : "Rejected")
<< " | event_id=" << ack.event_id
<< " | msg=" << ack.message << "\n\n";
// 2. 查询所有事件并展示
std::cout << "[2] 查询事件列表(默认顺序:创建时间倒序)\n";
auto events = etms::QueryAllEvents();
PrintEvents(events);
// 3. 筛选紧迫事件
std::cout << "[3] 筛选紧迫事件(等级 >= 8 ...\n";
auto urgent = etms::FilterUrgentEvents(events);
PrintEvents(urgent);
// 4. 事件排序:按等级降序
std::cout << "[4] 按等级降序排序 ...\n";
etms::SortEventsByLevelDesc(events);
PrintEvents(events);
// 5. 事件状态推进(模拟状态机)
std::cout << "[5] 推进事件状态 ...\n";
for (auto& evt : events) {
if (evt.status == etms::EventStatus::Received) {
// 先处理
etms::ProcessEvent(evt);
std::cout << " 事件 " << evt.event_id
<< "" << etms::EventStatusToString(evt.status) << "\n";
// 再推进到 PendingTask
etms::AdvanceEventStatus(evt);
std::cout << " 事件 " << evt.event_id
<< "" << etms::EventStatusToString(evt.status) << "\n";
}
}
std::cout << "\n";
// 6. 获取知识库版本与模板
std::cout << "[6] 获取知识库版本与模板 ...\n";
auto versions = etms::GetAvailableKbVersions();
PrintKbVersions(versions);
auto templates = etms::GetAvailableTemplates();
PrintTemplates(templates);
// 7. 自主推荐(模拟自主执行模式)
std::cout << "[7] 事件匹配推荐(自主执行模式) ...\n";
for (const auto& evt : events) {
auto recommended = etms::RecommendTemplate(evt, templates);
if (!recommended.empty()) {
std::cout << " 事件 " << evt.event_id << " (" << evt.event_type << ")"
<< " → 推荐模板: " << recommended << "\n";
}
}
std::cout << "\n";
// 8. 组装任务生成请求
std::cout << "[8] 组装任务生成请求 ...\n";
auto selected_event = events.front();
auto selected_tpl = templates.front();
std::map<std::string, std::string> params = {
{"target_coord", std::to_string(selected_event.longitude) + ","
+ std::to_string(selected_event.latitude)},
{"priority", std::to_string(selected_event.level)},
{"description", selected_event.description.substr(0, 100)}
};
auto request = etms::BuildTaskRequest(
selected_event.event_id,
selected_tpl.template_id,
versions.front().version_id,
params
);
std::cout << " 请求ID: " << request.request_id << "\n"
<< " 事件ID: " << request.event_id << "\n"
<< " 模板ID: " << request.template_id << "\n"
<< " 知识库版本: " << request.kb_version_id << "\n"
<< " 参数数量: " << request.params.size() << "\n"
<< " 请求时间: " << std::ctime(&request.request_time);
std::cout << "\n=== ETMS 演示流程完成 ===\n";
return 0;
}

249
tests/basic_test.cpp Normal file
View File

@ -0,0 +1,249 @@
/// @file basic_test.cpp
/// @brief ETMS 核心模块单元测试(使用标准库 assert无外部依赖
#include "app.hpp"
#include <cassert>
#include <iostream>
#include <sstream>
#include <string>
/// @brief 测试事件状态枚举与字符串转换。
static void test_EventStatusToString() {
std::cout << " [test] EventStatusToString ... ";
assert(std::string(etms::EventStatusToString(etms::EventStatus::Received)) == "Received");
assert(std::string(etms::EventStatusToString(etms::EventStatus::Processed)) == "Processed");
assert(std::string(etms::EventStatusToString(etms::EventStatus::PendingTask)) == "Pending Task");
assert(std::string(etms::EventStatusToString(etms::EventStatus::Rejected)) == "Rejected");
assert(std::string(etms::EventStatusToString(etms::EventStatus::TaskGenerated)) == "Task Generated");
std::cout << "PASSED\n";
}
/// @brief 测试接收原始事件(正常情况)。
static void test_ReceiveRawEvent_Valid() {
std::cout << " [test] ReceiveRawEvent (valid JSON) ... ";
const std::string json = R"({"event_id":"EVT-TEST-001","event_type":""})";
auto ack = etms::ReceiveRawEvent(json);
assert(ack.accepted == true);
assert(ack.event_id == "EVT-TEST-001");
assert(!ack.message.empty());
std::cout << "PASSED\n";
}
/// @brief 测试接收原始事件(空载荷应拒绝)。
static void test_ReceiveRawEvent_Empty() {
std::cout << " [test] ReceiveRawEvent (empty) ... ";
auto ack = etms::ReceiveRawEvent("");
assert(ack.accepted == false);
assert(ack.event_id.empty());
std::cout << "PASSED\n";
}
/// @brief 测试接收原始事件(缺少 event_id 应拒绝)。
static void test_ReceiveRawEvent_MissingId() {
std::cout << " [test] ReceiveRawEvent (missing event_id) ... ";
const std::string json = R"({"event_type":""})";
auto ack = etms::ReceiveRawEvent(json);
assert(ack.accepted == false);
std::cout << "PASSED\n";
}
/// @brief 测试处理事件:状态从 Received → Processed。
static void test_ProcessEvent() {
std::cout << " [test] ProcessEvent ... ";
etms::Event evt;
evt.event_id = "EVT-PROC-001";
evt.status = etms::EventStatus::Received;
bool ok = etms::ProcessEvent(evt);
assert(ok == true);
assert(evt.status == etms::EventStatus::Processed);
std::cout << "PASSED\n";
}
/// @brief 测试处理事件:非 Received 状态不应被处理。
static void test_ProcessEvent_WrongStatus() {
std::cout << " [test] ProcessEvent (wrong status) ... ";
etms::Event evt;
evt.status = etms::EventStatus::TaskGenerated;
bool ok = etms::ProcessEvent(evt);
assert(ok == false);
assert(evt.status == etms::EventStatus::TaskGenerated);
std::cout << "PASSED\n";
}
/// @brief 测试事件查询返回非空列表。
static void test_QueryAllEvents() {
std::cout << " [test] QueryAllEvents ... ";
auto events = etms::QueryAllEvents();
assert(!events.empty());
// 默认应倒序create_time 递减)
for (size_t i = 1; i < events.size(); ++i) {
assert(events[i - 1].create_time >= events[i].create_time);
}
std::cout << "PASSED (" << events.size() << " events)\n";
}
/// @brief 测试紧迫事件筛选。
static void test_FilterUrgentEvents() {
std::cout << " [test] FilterUrgentEvents ... ";
auto events = etms::QueryAllEvents();
auto urgent = etms::FilterUrgentEvents(events);
for (const auto& e : urgent) {
assert(e.level >= 8);
}
assert(!urgent.empty());
std::cout << "PASSED (" << urgent.size() << " urgent)\n";
}
/// @brief 测试模板推荐(匹配类型应返回对应模板 ID
static void test_RecommendTemplate() {
std::cout << " [test] RecommendTemplate ... ";
auto templates = etms::GetAvailableTemplates();
etms::Event recon_evt;
recon_evt.event_type = "侦察";
auto id1 = etms::RecommendTemplate(recon_evt, templates);
assert(id1 == "TMPL-RECON-001");
etms::Event strike_evt;
strike_evt.event_type = "打击";
auto id2 = etms::RecommendTemplate(strike_evt, templates);
assert(id2 == "TMPL-STRIKE-001");
// 不匹配类型时应返回兜底(第一个模板)
etms::Event unknown_evt;
unknown_evt.event_type = "未知";
auto id3 = etms::RecommendTemplate(unknown_evt, templates);
assert(id3 == templates.front().template_id);
std::cout << "PASSED\n";
}
/// @brief 测试空模板列表时的推荐行为。
static void test_RecommendTemplate_EmptyTemplates() {
std::cout << " [test] RecommendTemplate (empty list) ... ";
std::vector<etms::TaskTemplate> empty;
etms::Event evt;
evt.event_type = "侦察";
auto id = etms::RecommendTemplate(evt, empty);
assert(id.empty());
std::cout << "PASSED\n";
}
/// @brief 测试任务请求组装。
static void test_BuildTaskRequest() {
std::cout << " [test] BuildTaskRequest ... ";
std::map<std::string, std::string> params = {{"key1", "val1"}, {"key2", "val2"}};
auto req = etms::BuildTaskRequest("EVT-REQ-001", "TMPL-001", "KB-V1.0", params);
assert(req.request_id.find("REQ-") == 0);
assert(req.event_id == "EVT-REQ-001");
assert(req.template_id == "TMPL-001");
assert(req.kb_version_id == "KB-V1.0");
assert(req.params.size() == 2);
assert(req.request_time > 0);
std::cout << "PASSED\n";
}
/// @brief 测试知识库版本查询。
static void test_GetAvailableKbVersions() {
std::cout << " [test] GetAvailableKbVersions ... ";
auto versions = etms::GetAvailableKbVersions();
assert(!versions.empty());
bool has_active = false;
for (const auto& v : versions) {
if (v.status == "Active") has_active = true;
}
assert(has_active);
std::cout << "PASSED (" << versions.size() << " versions)\n";
}
/// @brief 测试模板查询。
static void test_GetAvailableTemplates() {
std::cout << " [test] GetAvailableTemplates ... ";
auto templates = etms::GetAvailableTemplates();
assert(!templates.empty());
for (const auto& t : templates) {
assert(!t.template_id.empty());
assert(!t.name.empty());
}
std::cout << "PASSED (" << templates.size() << " templates)\n";
}
/// @brief 测试事件状态推进机。
static void test_AdvanceEventStatus() {
std::cout << " [test] AdvanceEventStatus ... ";
etms::Event evt;
evt.status = etms::EventStatus::Received;
// Received → Processed
assert(etms::AdvanceEventStatus(evt) == true);
assert(evt.status == etms::EventStatus::Processed);
// Processed → PendingTask
assert(etms::AdvanceEventStatus(evt) == true);
assert(evt.status == etms::EventStatus::PendingTask);
// PendingTask → TaskGenerated
assert(etms::AdvanceEventStatus(evt) == true);
assert(evt.status == etms::EventStatus::TaskGenerated);
// TaskGenerated → 不可再推进
assert(etms::AdvanceEventStatus(evt) == false);
assert(evt.status == etms::EventStatus::TaskGenerated);
std::cout << "PASSED\n";
}
/// @brief 测试 Rejected 状态不可推进。
static void test_AdvanceEventStatus_Rejected() {
std::cout << " [test] AdvanceEventStatus (Rejected) ... ";
etms::Event evt;
evt.status = etms::EventStatus::Rejected;
assert(etms::AdvanceEventStatus(evt) == false);
assert(evt.status == etms::EventStatus::Rejected);
std::cout << "PASSED\n";
}
/// @brief 测试排序函数(按等级降序)。
static void test_SortEventsByLevelDesc() {
std::cout << " [test] SortEventsByLevelDesc ... ";
auto events = etms::QueryAllEvents();
etms::SortEventsByLevelDesc(events);
for (size_t i = 1; i < events.size(); ++i) {
assert(events[i - 1].level >= events[i].level);
}
std::cout << "PASSED\n";
}
/// @brief 测试排序函数(按时间升序)。
static void test_SortEventsByTimeAsc() {
std::cout << " [test] SortEventsByTimeAsc ... ";
auto events = etms::QueryAllEvents();
etms::SortEventsByTimeAsc(events);
for (size_t i = 1; i < events.size(); ++i) {
assert(events[i - 1].timestamp <= events[i].timestamp);
}
std::cout << "PASSED\n";
}
/// @brief 主测试入口。
int main() {
std::cout << "=== ETMS Basic Unit Tests ===\n\n";
test_EventStatusToString();
test_ReceiveRawEvent_Valid();
test_ReceiveRawEvent_Empty();
test_ReceiveRawEvent_MissingId();
test_ProcessEvent();
test_ProcessEvent_WrongStatus();
test_QueryAllEvents();
test_FilterUrgentEvents();
test_RecommendTemplate();
test_RecommendTemplate_EmptyTemplates();
test_BuildTaskRequest();
test_GetAvailableKbVersions();
test_GetAvailableTemplates();
test_AdvanceEventStatus();
test_AdvanceEventStatus_Rejected();
test_SortEventsByLevelDesc();
test_SortEventsByTimeAsc();
std::cout << "\n=== All " << 17 << " tests PASSED ===\n";
return 0;
}