296 lines
12 KiB
Markdown
296 lines
12 KiB
Markdown
|
|
# 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.cc(14 用例)
|
|||
|
|
|
|||
|
|
测试 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 registerRawExpression(1 用例)
|
|||
|
|
|
|||
|
|
| 用例 | 验证内容 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `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.cc(11 用例)
|
|||
|
|
|
|||
|
|
测试 FbStateMachine 的完整 7 状态生命周期。
|
|||
|
|
|
|||
|
|
### 2.1 初始状态(1 用例)
|
|||
|
|
|
|||
|
|
| 用例 | 验证内容 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `initial_state_is_idle` | 新建 FSM 的 `currentState()` 为 `FbState::Idle`,`isActive()` 为 false |
|
|||
|
|
|
|||
|
|
### 2.2 Idle → Started(2 用例)
|
|||
|
|
|
|||
|
|
| 用例 | 验证内容 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `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 → Done(1 用例)
|
|||
|
|
|
|||
|
|
| 用例 | 验证内容 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `started_proceeds_to_done_via_feedback` | Started → InProgress(1-2 周期)→ `checkFeedback(true)` → Done → 自动回到 Idle |
|
|||
|
|
|
|||
|
|
### 2.4 NotHold(1 用例)
|
|||
|
|
|
|||
|
|
| 用例 | 验证内容 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `keep_mode_not_hold_when_trigger_lost` | `keep_mode=true` 时触发条件丢失 → `FbState::NotHold`,`funVarsNeedReset=true` |
|
|||
|
|
|
|||
|
|
### 2.5 Timeout(1 用例)
|
|||
|
|
|
|||
|
|
| 用例 | 验证内容 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `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 forceReset(1 用例)
|
|||
|
|
|
|||
|
|
| 用例 | 验证内容 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `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.cc(52 用例)
|
|||
|
|
|
|||
|
|
由于算法子类(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 = 1,bit 0 of 8 = 0 |
|
|||
|
|
| `fault_code_bit_parsing_all_bits` | 0x0F → 4 个置位 bit |
|
|||
|
|
| `fault_code_bit_15_set` | bit 15(0x8000)单独置位 |
|
|||
|
|
| `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 用例)
|
|||
|
|
|
|||
|
|
#### extractTagNumbers(7 用例)
|
|||
|
|
|
|||
|
|
验证从 `"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]` |
|
|||
|
|
|
|||
|
|
#### calculateMedian(7 用例)
|
|||
|
|
|
|||
|
|
验证中位数计算。
|
|||
|
|
|
|||
|
|
| 用例 | 验证内容 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `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 连接,未在单元测试中覆盖。
|