生成代码工程
This commit is contained in:
parent
5b3474c57a
commit
3afea1e4c1
|
|
@ -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..."
|
||||
)
|
||||
58
README.md
58
README.md
|
|
@ -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` | 演示全流程(事件接收→展示→模板选择→请求组装) |
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue