test: FbStateMachine 状态转换单元测试

This commit is contained in:
Huamonarch 2026-05-15 13:27:27 +08:00
parent 9f66fc10b3
commit fad4ee8e38
2 changed files with 198 additions and 0 deletions

View File

@ -101,6 +101,7 @@ aux_source_directory(./test TEST_SOURCES)
add_executable(eqpalg_test add_executable(eqpalg_test
${TEST_SOURCES} ${TEST_SOURCES}
./utility/expression_engine.cpp ./utility/expression_engine.cpp
./utility/fb_state_machine.cpp
) )
target_include_directories(eqpalg_test PUBLIC target_include_directories(eqpalg_test PUBLIC

View File

@ -0,0 +1,197 @@
// eqpalg/test/test_fb_state_machine.cc
#include "test_harness.h"
#include <eqpalg/utility/fb_state_machine.h>
#include <chrono>
#include <map>
#include <string>
using namespace std::chrono;
// 测试辅助:构建最小环境
struct FbTestEnv {
std::map<std::string, double> vars;
FbStateMachine fsm;
TimePoint now;
FbTestEnv(size_t tag_count = 2) {
// 模拟已初始化的变量状态
for (size_t i = 0; i < tag_count; i++) {
std::string idx = std::to_string(i + 1);
vars["tag" + idx] = 0.0;
vars["p" + idx] = 0.0;
vars["now"] = 0;
}
now = std::chrono::system_clock::now();
vars["now"] = duration_cast<milliseconds>(now.time_since_epoch()).count();
}
void setTag(int n, double val) {
std::string idx = std::to_string(n);
vars["p" + idx] = vars["tag" + idx]; // p = old tag
vars["tag" + idx] = val;
}
void advanceTime(int ms) {
now += milliseconds(ms);
vars["now"] = duration_cast<milliseconds>(now.time_since_epoch()).count();
}
FbUpdateResult step(bool trigger) {
return fsm.update(trigger, now, vars, 2);
}
};
// ==================== 初始状态 ====================
TEST(initial_state_is_idle) {
FbTestEnv env;
CHECK(env.fsm.currentState() == FbState::Idle);
CHECK_EQ(env.fsm.isActive(), false);
}
// ==================== Idle → Started ====================
TEST(idle_to_started_when_triggered) {
FbTestEnv env;
auto result = env.step(true);
CHECK(result.state == FbState::Started);
CHECK_EQ(env.fsm.isActive(), true);
CHECK_EQ(result.funVarsNeedReset, false);
}
TEST(idle_stays_idle_when_not_triggered) {
FbTestEnv env;
auto result = env.step(false);
CHECK(result.state == FbState::Idle);
CHECK_EQ(result.funVarsNeedReset, true); // 空闲时重置 fun_vars
}
// ==================== Started → InProgress → Done ====================
TEST(started_proceeds_to_done_via_feedback) {
FbTestEnv env;
// 首次触发 → Started
auto r1 = env.step(true);
CHECK(r1.state == FbState::Started);
// Started 自动推进到 InProgress第二次 update
auto r2 = env.step(true);
CHECK(r2.state == FbState::InProgress || r2.state == FbState::Started);
// 如果第二次还在 Started第三次一定到 InProgress
if (r2.state == FbState::Started) {
r2 = env.step(true);
}
CHECK(r2.state == FbState::InProgress);
// 反馈条件满足 → Done
bool done = env.fsm.checkFeedback(true, env.now, env.vars);
CHECK_EQ(done, true);
CHECK(env.fsm.currentState() == FbState::Idle); // 自动回到 Idle
}
// ==================== NotHold ====================
TEST(keep_mode_not_hold_when_trigger_lost) {
FbTestEnv env;
env.fsm.configure(true, milliseconds(600000)); // keep_mode=true
// 触发 → Started
env.step(true);
// → InProgress
env.step(true);
// 触发丢失 → NotHold
auto r = env.step(false);
CHECK(r.state == FbState::NotHold);
CHECK_EQ(r.funVarsNeedReset, true);
}
// ==================== Timeout ====================
TEST(timeout_when_exceeds_limit) {
FbTestEnv env;
env.fsm.configure(false, milliseconds(100)); // 100ms timeout
// 触发 → Started → InProgress
env.step(true);
env.step(true);
// 超时
env.advanceTime(200);
auto r = env.step(true);
CHECK(r.state == FbState::Timeout);
CHECK_EQ(r.funVarsNeedReset, true);
}
// ==================== 变量快照 ====================
TEST(snapshot_on_action_start) {
FbTestEnv env;
env.setTag(1, 3.0);
env.setTag(2, 7.0);
env.step(true); // → Started快照发生
CHECK_FLOAT_EQ(env.vars["s1"], 3.0, 0.001);
CHECK_FLOAT_EQ(env.vars["s2"], 7.0, 0.001);
CHECK_FLOAT_EQ(env.vars["time"], 0.0, 0.001);
CHECK_FLOAT_EQ(env.vars["mv2_tag1"], 0.0, 0.001);
// stime 应该被设置
CHECK(env.vars["stime"] > 0);
}
// ==================== 变量累积 ====================
TEST(action_vars_accumulate_in_progress) {
FbTestEnv env;
env.setTag(1, 1.0); // tag1=1
env.setTag(2, 0.0);
env.step(true); // Started
env.step(true); // InProgress (累积发生)
CHECK_EQ(env.vars["mv2_tag1"] >= 1.0, true); // tag1==1 被计数
CHECK_FLOAT_EQ(env.vars["mx_tag1"], 1.0, 0.001);
CHECK_FLOAT_EQ(env.vars["mi_tag2"], 0.0, 0.001);
}
// ==================== forceReset ====================
TEST(force_reset_returns_to_idle) {
FbTestEnv env;
env.step(true); // Started
CHECK_EQ(env.fsm.isActive(), true);
env.fsm.forceReset();
CHECK(env.fsm.currentState() == FbState::Idle);
CHECK_EQ(env.fsm.isActive(), false);
}
// ==================== 非 keep 模式下触发丢失 ====================
TEST(no_keep_mode_trigger_loss_stays_in_progress) {
FbTestEnv env;
env.fsm.configure(false, milliseconds(600000)); // keep_mode=false
env.step(true); // Started
env.step(true); // InProgress
auto r = env.step(false); // 触发丢失但 keep_mode=false
CHECK(r.state == FbState::InProgress); // 不退出
}
// ==================== 终端状态自动回归 Idle ====================
TEST(terminal_state_returns_to_idle_next_cycle) {
FbTestEnv env;
env.fsm.configure(false, milliseconds(10));
env.step(true);
env.step(true);
env.advanceTime(20);
auto r = env.step(true);
CHECK(r.state == FbState::Timeout);
// 下一周期自动回到 Idle
auto r2 = env.step(false);
CHECK(r2.state == FbState::Idle);
}