250 lines
8.8 KiB
C++
250 lines
8.8 KiB
C++
|
|
/// @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;
|
|||
|
|
}
|