eis/eqpalg/test/README.md

296 lines
12 KiB
Markdown
Raw Normal View History

# eqpalg 测试说明文档
## 概述
eqpalg 测试采用轻量级自注册框架(`test_harness.h`),无 Boost.Test 依赖。测试入口为 `test_main.cc`,所有 `TEST(name)` 宏定义的用例通过静态构造函数自动注册。
**构建与运行**
```bash
cd eqpalg/build
cmake .. -DCMAKE_BUILD_TYPE=Debug
make -j$(nproc)
cd test
./eqpalg_test
```
---
## 测试文件清单
| 文件 | 用例数 | 被测组件 |
|------|--------|---------|
| `test_expression_engine.cc` | 14 | ExpressionEngine — 表达式注册、求值、FunVars 重置 |
| `test_fb_state_machine.cc` | 11 | FbStateMachine — 7 状态反馈状态机 |
| `test_algorithms.cc` | 52 | BoundChecker + 算法核心逻辑 + Roller3/FaultCode 工具函数 |
**总计**77 个测试用例
---
## 一、test_expression_engine.cc14 用例)
测试 ExpressionEngine 的核心 API。
### 1.1 注册与求值5 用例)
| 用例 | 验证内容 |
|------|---------|
| `register_and_evaluate_simple_expression` | `registerExpression` 返回 0`evaluate` 返回正确数值,`evaluateBool` 返回正确布尔值 |
| `register_duplicate_is_idempotent` | 重复注册同名表达式是幂等操作,保留首次注册的表达式 |
| `evaluate_unregistered_returns_zero` | 未注册表达式名求值返回 0.0 / false |
| `evaluate_zero_expression` | 表达式 `"0"` 求值为 0.0`evaluateBool` 为 false |
| `evaluate_boolean_true_constant` | 表达式 `"1"``evaluateBool` 为 true |
### 1.2 变量变化1 用例)
| 用例 | 验证内容 |
|------|---------|
| `variable_change_reflected_in_evaluation` | 修改 `mm_vars``evaluate` 立即反映新值 |
### 1.3 多表达式并存1 用例)
| 用例 | 验证内容 |
|------|---------|
| `multiple_expressions_independent` | 3 个表达式独立求值,变量更新后各自正确反映 |
### 1.4 registerRawExpression1 用例)
| 用例 | 验证内容 |
|------|---------|
| `register_raw_no_funvars_processing` | `registerRawExpression` 跳过 FunVars 状态函数处理,直接编译原始表达式 |
### 1.5 FunVars 重置控制3 用例)
| 用例 | 验证内容 |
|------|---------|
| `autoReset_does_nothing_when_not_marked` | 未标记时 `autoResetFunVars` 是 no-op |
| `mark_and_autoReset_sequence` | `markFunVarsNeedReset` + `autoResetFunVars` 联合工作,重置后标志清除 |
| `forceReset_works` | `forceResetFunVars` 立即执行,无延迟 |
### 1.6 复杂表达式3 用例)
| 用例 | 验证内容 |
|------|---------|
| `comparison_expression` | 比较表达式 `"tag1 > tag2"`,变量更新后布尔结果正确翻转 |
| `arithmetic_with_comparison` | 算术表达式 `"tag1 * 2 + tag2"` |
---
## 二、test_fb_state_machine.cc11 用例)
测试 FbStateMachine 的完整 7 状态生命周期。
### 2.1 初始状态1 用例)
| 用例 | 验证内容 |
|------|---------|
| `initial_state_is_idle` | 新建 FSM 的 `currentState()``FbState::Idle``isActive()` 为 false |
### 2.2 Idle → Started2 用例)
| 用例 | 验证内容 |
|------|---------|
| `idle_to_started_when_triggered` | `actTriggered=true``FbState::Started``funVarsNeedReset=false` |
| `idle_stays_idle_when_not_triggered` | `actTriggered=false` → 保持 `Idle``funVarsNeedReset=true`(空闲时重置) |
### 2.3 Started → InProgress → Done1 用例)
| 用例 | 验证内容 |
|------|---------|
| `started_proceeds_to_done_via_feedback` | Started → InProgress1-2 周期)→ `checkFeedback(true)` → Done → 自动回到 Idle |
### 2.4 NotHold1 用例)
| 用例 | 验证内容 |
|------|---------|
| `keep_mode_not_hold_when_trigger_lost` | `keep_mode=true` 时触发条件丢失 → `FbState::NotHold``funVarsNeedReset=true` |
### 2.5 Timeout1 用例)
| 用例 | 验证内容 |
|------|---------|
| `timeout_when_exceeds_limit` | 超过 `timeout` 时间 → `FbState::Timeout``funVarsNeedReset=true` |
### 2.6 变量快照1 用例)
| 用例 | 验证内容 |
|------|---------|
| `snapshot_on_action_start` | Started 状态下,`s1`/`s2` 快照正确,`stime` 已设置,`time=0``mv2_tagN` 初始化为 0 |
### 2.7 变量累积1 用例)
| 用例 | 验证内容 |
|------|---------|
| `action_vars_accumulate_in_progress` | InProgress 状态下,`mv2_tagN` 正确累加,`mx_tagN`/`mi_tagN` 跟踪极值 |
### 2.8 forceReset1 用例)
| 用例 | 验证内容 |
|------|---------|
| `force_reset_returns_to_idle` | `forceReset()` → 状态回到 Idle`isActive()` 变为 false |
### 2.9 非 keep 模式触发丢失1 用例)
| 用例 | 验证内容 |
|------|---------|
| `no_keep_mode_trigger_loss_stays_in_progress` | `keep_mode=false` 时触发丢失不退出 InProgress |
### 2.10 终端状态自动回归1 用例)
| 用例 | 验证内容 |
|------|---------|
| `terminal_state_returns_to_idle_next_cycle` | Timeout 后下一周期 `update` 返回 Idle |
---
## 三、test_algorithms.cc52 用例)
由于算法子类LogicAlg/BoundAlg 等)的构造函数依赖 CMemVar 共享内存等运行时基础设施,本测试文件采用**组件组合模拟**策略:不完整构造算法对象,而是测试已提取的独立组件和算法特有逻辑。
### 3.1 LogicAlg 核心逻辑6 用例)
验证 `LogicAlg::doMonProc()` 使用的表达式求值流程。
| 用例 | 验证内容 |
|------|---------|
| `logic_alg_trigger_true_produces_alarm` | 表达式为 true → 应报警 |
| `logic_alg_trigger_false_no_alarm` | 表达式为 false → 不报警 |
| `logic_alg_complex_expression` | `tag1 > 2 && tag2 < 10` 组合条件 |
| `logic_alg_and_short_circuit_false` | AND 条件中一个为 false 整体为 false |
| `logic_alg_or_expression` | OR 条件中一个为 true 整体为 true |
| `logic_alg_negation_operator` | `!tag1` 取反运算符(`!` 是项目新增的 matheval 运算符) |
### 3.2 BoundChecker 检测器11 用例)
验证 `BoundAlg::doMonProc()` 使用的上下限检测逻辑。
| 用例 | 验证内容 |
|------|---------|
| `bound_checker_detects_out_of_upper` | 值超上限 → `isOutOfBounds=true` |
| `bound_checker_detects_out_of_lower` | 值超下限 → `isOutOfBounds=true` |
| `bound_checker_only_right_mode_sentinel` | `limit_down=-32768` → 自动推导 `OnlyRight` 模式,仅检测上限 |
| `bound_checker_only_left_mode_sentinel` | `limit_up=32767` → 自动推导 `OnlyLeft` 模式,仅检测下限 |
| `bound_checker_only_left_mode_sentinel_32768` | `limit_up=32768` 同样为哨兵值 |
| `bound_checker_default_bilateral` | 正常上下限 → `Default` 双侧检测 |
| `bound_checker_error_mode` | 双哨兵 `(-32768, -32768)``ErrorMode`,永不报警 |
| `bound_checker_exact_boundary_default` | 等于限值的边界值不触发报警 |
| `bound_checker_boundary_only_left` | OnlyLeft 模式下的边界行为 |
| `bound_checker_boundary_only_right` | OnlyRight 模式下的边界行为 |
| `bound_checker_isValid` + `setDetectMode_override` | `isValid()` 查询 + `setDetectMode` 手动覆盖 |
### 3.3 BoundAlg 过滤表达式2 用例)
| 用例 | 验证内容 |
|------|---------|
| `bound_alg_filter_expression` | `exp_feedback_` 过滤条件为 false 时不参与统计,为 true 时参与 |
| `bound_alg_filter_boundary` | 过滤表达式边界值 `>=` 检查 |
### 3.4 BoundHoldAlg 保持时间3 用例)
| 用例 | 验证内容 |
|------|---------|
| `bound_hold_time_logic` | 值需持续超限 `hold_time` 后才报警,`hold_time <= delay_time` 时立即报警 |
| `bound_hold_zero_hold_time` | `hold_time=0` → 立即报警 |
| `bound_hold_long_delay` | 长时间保持60s到期前不报警到期后报警 |
### 3.5 FeedbackAlg 集成3 用例)
验证 ExpressionEngine + FbStateMachine 组合行为。
| 用例 | 验证内容 |
|------|---------|
| `feedback_full_flow_start_to_done` | 触发 → Started → InProgress → 等待反馈条件 |
| `feedback_full_flow_not_hold` | keep_mode 下触发丢失 → NotHold`funVarsNeedReset=true` |
| `feedback_timeout_scenario` | 短超时100ms→ Timeout |
### 3.6 ExpTimes 累积逻辑4 用例)
| 用例 | 验证内容 |
|------|---------|
| `exp_times_occurrence_counting_logic` | 6 次触发 → `shear_times=6` > `max_times=5` → 报警 |
| `exp_times_occurrence_below_threshold` | 3 次触发 → 低于阈值 → 不报警 |
| `exp_times_time_accumulation_logic` | 时间累积5 秒 → 转换为小时5000/3600000 |
| `exp_times_time_multiple_intervals` | 多段时间累积3s + 7s = 10s |
### 3.7 FaultCode bit 提取6 用例)
| 用例 | 验证内容 |
|------|---------|
| `fault_code_gitbit_extraction` | 基本位提取bit 3 of 8 = 1bit 0 of 8 = 0 |
| `fault_code_bit_parsing_all_bits` | 0x0F → 4 个置位 bit |
| `fault_code_bit_15_set` | bit 150x8000单独置位 |
| `fault_code_all_bits_set_16bit` | 0xFFFF → 16 位全置位 |
| `fault_code_single_bit_each_position` | 每个 bit 位置独立验证 |
| `fault_code_gitbit_with_different_types` | `unsigned int`/`short`/`long` 类型兼容性 |
### 3.8 Roller3 工具函数14 用例)
#### extractTagNumbers7 用例)
验证从 `"tag1+tag2+tag3"` 表达式中提取 tag 序号。
| 用例 | 验证内容 |
|------|---------|
| `roller3_extract_tag_numbers` | `"tag1+tag2+tag3"``[1, 2, 3]` |
| `roller3_extract_tag_numbers_single` | `"tag5"``[5]` |
| `roller3_extract_tag_numbers_complex` | `"tag10+tag2+tag35"` → 包含 10, 2, 35 |
| `roller3_extract_empty_string` | 空字符串 → 空结果 |
| `roller3_extract_no_tags` | 无 tag 前缀 → 空结果 |
| `roller3_extract_tag_numbers_with_prefix` | `"metatag1+tag2"` → 提取 `tag1``tag2`(子串匹配特性) |
| `roller3_extract_large_tag_numbers` | `"tag999+tag1000"``[999, 1000]` |
#### calculateMedian7 用例)
验证中位数计算。
| 用例 | 验证内容 |
|------|---------|
| `roller3_calculate_median_odd` | 奇数元素:`[1,3,5]` → 3.0`[10,2,8]` → 8.0(内部排序) |
| `roller3_calculate_median_even` | 偶数元素:`[1,3,5,7]` → 4.0`[1,2]` → 1.5 |
| `roller3_calculate_median_single` | 单元素:`[42]` → 42.0 |
| `roller3_calculate_median_empty` | 空数组 → 0.0 |
| `roller3_calculate_median_negative_values` | 负数:`[-5,-1,-3]` → -3.0 |
| `roller3_calculate_median_large_dataset` | 大数据集:`[1..99]` → 50.0 |
| `roller3_calculate_median_unsorted_preserves_order` | 乱序输入 → 内部排序后正确 |
### 3.9 JSON 配置校验5 用例)
验证各算法类型的最小合法 JSON 结构完整性。
| 用例 | 验证内容 |
|------|---------|
| `json_config_logic_alg_structure` | LogicAlg JSON 包含 tags/trigger/function/output |
| `json_config_bound_alg_structure` | BoundAlg JSON 包含 limit_down/limit_up |
| `json_config_feedback_logic_structure` | FeedbackAlg 逻辑型 JSON 包含 action_start/action_end/timeout |
| `json_config_feedback_bound_structure` | FeedbackAlg 上下限型 JSON 包含 bound params |
| `json_config_bound_hold_structure` | BoundHoldAlg JSON 包含 hold_time |
---
## 测试框架说明
### 宏
| 宏 | 用途 |
|----|------|
| `TEST(name)` | 定义一个测试用例,自动注册到 TestRunner |
| `CHECK(expr)` | 断言 expr 为 true |
| `CHECK_EQ(a, b)` | 断言 a == b |
| `CHECK_FLOAT_EQ(a, b, eps)` | 断言 `abs(a-b) <= eps` |
| `CHECK_THROWS(expr)` | 断言 expr 抛出异常 |
### 运行指定测试
测试按文件编译为独立可执行文件 `eqpalg_test`,所有用例顺序执行,输出 PASSED/FAILED 及汇总。
---
## 已知限制
1. **算法完整构造测试**LogicAlg/BoundAlg/FeedbackAlg 等算法子类的构造函数依赖 `CMemVar::Const()` 共享内存全局变量无法在开发机上进行完整的端到端测试。当前测试策略是通过组件组合ExpressionEngine + FbStateMachine + BoundChecker模拟 `doMonProc()` 的控制流。
2. **IHDB 依赖算法**TrendSlope2/3、Roller、GlitchDetection 等算法依赖 iHyperDB 查询,其 `exec_mon()` 无法在纯单元测试中运行。这些算法的核心逻辑斜率计算、中位数离群检测、bit 提取)已在上面的测试中覆盖。
3. **DB2 依赖**StatCollector、FaultCode 的数据库操作部分需要 DB2 连接,未在单元测试中覆盖。