From e54cc32839acdd00ef7d448a93e1874443b1c35e Mon Sep 17 00:00:00 2001 From: linianlin Date: Fri, 1 May 2026 14:32:03 +0800 Subject: [PATCH] =?UTF-8?q?AI=20=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/CMakeLists.txt | 25 ++++ tests/test_app.cpp | 282 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+) create mode 100644 tests/CMakeLists.txt create mode 100644 tests/test_app.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..31a42ad --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.10.0) +project(test_task_auto_plan_execute_project) +include(FetchContent) +if (MSVC) + add_compile_options(/utf-8) +endif() +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) + +include(CTest) +enable_testing() + +add_executable(test_task_auto_plan_execute_project test_app.cpp ../src/app.cpp) + +target_link_libraries(test_task_auto_plan_execute_project gtest gmock gtest_main) +include(GoogleTest) +gtest_discover_tests(test_task_auto_plan_execute_project) \ No newline at end of file diff --git a/tests/test_app.cpp b/tests/test_app.cpp new file mode 100644 index 0000000..e606493 --- /dev/null +++ b/tests/test_app.cpp @@ -0,0 +1,282 @@ +#include +#include "app.hpp" +#include +#include + +namespace c2sys { + +class AppTest : public ::testing::Test { +protected: + App app; + void SetUp() override { + app.initialize(""); + } +}; + +// generateId tests +TEST(AppTest, GenerateIdFormat) { + std::string id = app.generateId(); + EXPECT_TRUE(id.find("ID-") == 0); + EXPECT_EQ(id.length(), 23u); +} + +TEST(AppTest, GenerateIdUniqueness) { + std::string id1 = app.generateId(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::string id2 = app.generateId(); + EXPECT_NE(id1, id2); +} + +// nowMs tests +TEST(AppTest, NowMsReturnsPositive) { + int64_t ms = app.nowMs(); + EXPECT_GT(ms, 0); +} + +// Impl constructor tests +TEST(AppTest, InitialState) { + EXPECT_EQ(app.getState(), SystemState::Ready); + EXPECT_EQ(app.getRunMode(), RunMode::HumanInLoop); +} + +// initialize tests +TEST_F(AppTest, InitializeWithEmptyConfig) { + EXPECT_TRUE(app.initialize("")); + EXPECT_EQ(app.getState(), SystemState::Ready); +} + +TEST_F(AppTest, InitializeClearsData) { + app.addPlan({"plan1", PlanType::Centralized, 0.5, 10, 0.8, 0.7, 0.9}); + app.initialize(""); + EXPECT_TRUE(app.getAllPlans().empty()); +} + +// start tests +TEST_F(AppTest, StartFromReady) { + EXPECT_TRUE(app.start()); + EXPECT_EQ(app.getState(), SystemState::Running); +} + +TEST_F(AppTest, StartFromStopped) { + app.stop(); + EXPECT_TRUE(app.start()); + EXPECT_EQ(app.getState(), SystemState::Running); +} + +TEST_F(AppTest, StartFromRunningFails) { + app.start(); + EXPECT_FALSE(app.start()); +} + +// stop tests +TEST_F(AppTest, StopChangesState) { + app.start(); + app.stop(); + EXPECT_EQ(app.getState(), SystemState::Stopped); +} + +// getState tests +TEST_F(AppTest, GetStateAfterStart) { + app.start(); + EXPECT_EQ(app.getState(), SystemState::Running); +} + +// setRunMode tests +TEST_F(AppTest, SetRunModeUpdatesCache) { + app.setRunMode(RunMode::Autonomous); + EXPECT_EQ(app.getRunMode(), RunMode::Autonomous); +} + +// getRunMode tests +TEST_F(AppTest, GetRunModeDefault) { + EXPECT_EQ(app.getRunMode(), RunMode::HumanInLoop); +} + +// addPlan tests +TEST_F(AppTest, AddValidPlan) { + PlanData plan{"p1", PlanType::Distributed, 0.6, 15, 0.9, 0.8, 0.7}; + EXPECT_TRUE(app.addPlan(plan)); + EXPECT_EQ(app.getAllPlans().size(), 1u); +} + +TEST_F(AppTest, AddEmptyIdPlanFails) { + PlanData plan{"", PlanType::Centralized, 0.5, 10, 0.8, 0.7, 0.9}; + EXPECT_FALSE(app.addPlan(plan)); +} + +TEST_F(AppTest, AddDuplicatePlanFails) { + PlanData plan{"p1", PlanType::Centralized, 0.5, 10, 0.8, 0.7, 0.9}; + app.addPlan(plan); + EXPECT_FALSE(app.addPlan(plan)); +} + +// getAllPlans tests +TEST_F(AppTest, GetAllPlansReturnsAll) { + app.addPlan({"p1", PlanType::Centralized, 0.5, 10, 0.8, 0.7, 0.9}); + app.addPlan({"p2", PlanType::Distributed, 0.6, 15, 0.9, 0.8, 0.7}); + EXPECT_EQ(app.getAllPlans().size(), 2u); +} + +// findPlanById tests +TEST_F(AppTest, FindExistingPlan) { + app.addPlan({"p1", PlanType::Centralized, 0.5, 10, 0.8, 0.7, 0.9}); + EXPECT_NE(app.findPlanById("p1"), nullptr); +} + +TEST_F(AppTest, FindNonExistingPlan) { + EXPECT_EQ(app.findPlanById("invalid"), nullptr); +} + +// comparePlans tests +TEST_F(AppTest, CompareValidPlans) { + app.addPlan({"p1", PlanType::Centralized, 0.5, 10, 0.8, 0.7, 0.9}); + std::string report = app.comparePlans({"p1"}); + EXPECT_TRUE(report.find("集中式") != std::string::npos); +} + +TEST_F(AppTest, CompareMissingPlan) { + std::string report = app.comparePlans({"missing"}); + EXPECT_TRUE(report.find("未找到") != std::string::npos); +} + +// ingestRawEvent tests +TEST_F(AppTest, IngestValidEvent) { + EventRaw raw{"src1", "payload", 3, "TCP"}; + std::string id = app.ingestRawEvent(raw); + EXPECT_FALSE(id.empty()); +} + +TEST_F(AppTest, IngestEmptySourceFails) { + EventRaw raw{"", "payload", 3, "TCP"}; + EXPECT_TRUE(app.ingestRawEvent(raw).empty()); +} + +// getPendingEvents tests +TEST_F(AppTest, GetPendingAfterIngest) { + EventRaw raw{"src1", "payload", 3, "TCP"}; + app.ingestRawEvent(raw); + EXPECT_EQ(app.getPendingEvents().size(), 1u); +} + +// processEvent tests +TEST_F(AppTest, ProcessAcceptEvent) { + EventRaw raw{"src1", "payload", 3, "TCP"}; + std::string id = app.ingestRawEvent(raw); + EXPECT_TRUE(app.processEvent(id, true)); + EXPECT_EQ(app.getPendingEvents().size(), 0u); +} + +TEST_F(AppTest, ProcessInvalidEventFails) { + EXPECT_FALSE(app.processEvent("invalid", true)); +} + +// generateTaskFromEvent tests +TEST_F(AppTest, GenerateTaskFromPendingEvent) { + EventRaw raw{"src1", "payload", 3, "TCP"}; + std::string evtId = app.ingestRawEvent(raw); + std::string taskId = app.generateTaskFromEvent(evtId); + EXPECT_FALSE(taskId.empty()); + EXPECT_NE(app.getExecutionStatus(taskId), nullptr); +} + +TEST_F(AppTest, GenerateTaskFromIgnoredEventFails) { + EventRaw raw{"src1", "payload", 3, "TCP"}; + std::string evtId = app.ingestRawEvent(raw); + app.processEvent(evtId, false); + EXPECT_TRUE(app.generateTaskFromEvent(evtId).empty()); +} + +// addTemplate tests +TEST_F(AppTest, AddValidTemplate) { + TaskTemplate tmpl{"t1", "scenario", 0.8}; + EXPECT_TRUE(app.addTemplate(tmpl)); +} + +TEST_F(AppTest, AddEmptyIdTemplateFails) { + TaskTemplate tmpl{"", "scenario", 0.8}; + EXPECT_FALSE(app.addTemplate(tmpl)); +} + +// matchBestTemplate tests +TEST_F(AppTest, MatchExistingTemplate) { + app.addTemplate({"t1", "threat_3", 0.9}); + EXPECT_NE(app.matchBestTemplate("threat_3"), nullptr); +} + +TEST_F(AppTest, MatchNoTemplate) { + EXPECT_EQ(app.matchBestTemplate("unknown"), nullptr); +} + +// saveSnapshot tests +TEST_F(AppTest, SaveSnapshotReturnsVersion) { + std::string ver = app.saveSnapshot(); + EXPECT_TRUE(ver.find("SNAP-") == 0); +} + +// rollbackToSnapshot tests +TEST_F(AppTest, RollbackValidSnapshot) { + std::string ver = app.saveSnapshot(); + EXPECT_TRUE(app.rollbackToSnapshot(ver)); +} + +TEST_F(AppTest, RollbackInvalidSnapshotFails) { + EXPECT_FALSE(app.rollbackToSnapshot("invalid")); +} + +// dispatchPlan tests +TEST_F(AppTest, DispatchValidPlan) { + app.addPlan({"p1", PlanType::Centralized, 0.5, 10, 0.8, 0.7, 0.9}); + int count = app.dispatchPlan("p1", {"node1", "node2"}); + EXPECT_GE(count, 0); + EXPECT_LE(count, 2); +} + +TEST_F(AppTest, DispatchInvalidPlanFails) { + EXPECT_EQ(app.dispatchPlan("invalid", {"node1"}), 0); +} + +// getDistributionAcks tests +TEST_F(AppTest, GetAcksAfterDispatch) { + app.addPlan({"p1", PlanType::Centralized, 0.5, 10, 0.8, 0.7, 0.9}); + app.dispatchPlan("p1", {"node1"}); + EXPECT_FALSE(app.getDistributionAcks().empty()); +} + +// reportExecutionStatus tests +TEST_F(AppTest, ReportStatusUpdatesMap) { + ExecutionStatus status{"task1", "PHASE1", 50.0, 1000, 0}; + app.reportExecutionStatus(status); + EXPECT_NE(app.getExecutionStatus("task1"), nullptr); +} + +// getExecutionStatus tests +TEST_F(AppTest, GetExistingStatus) { + ExecutionStatus status{"task1", "PHASE1", 50.0, 1000, 0}; + app.reportExecutionStatus(status); + EXPECT_NE(app.getExecutionStatus("task1"), nullptr); +} + +TEST_F(AppTest, GetNonExistingStatus) { + EXPECT_EQ(app.getExecutionStatus("invalid"), nullptr); +} + +// logOperation tests +TEST_F(AppTest, LogOperationAddsEntry) { + OperationLog log{"op1", "action", 1000}; + app.logOperation(log); + EXPECT_EQ(app.getOperationLogs().size(), 1u); +} + +// getOperationLogs tests +TEST_F(AppTest, GetLogsAfterLogging) { + app.logOperation({"op1", "action", 1000}); + EXPECT_FALSE(app.getOperationLogs().empty()); +} + +// getConfig tests +TEST_F(AppTest, GetConfigReturnsReference) { + const auto& config = app.getConfig(); + EXPECT_EQ(config.maxRetryCount, 3); +} + +} // namespace c2sys \ No newline at end of file