Files
oak-editor/docs/zh/plans/riir/03-testing.md
T
Mike-Solar 774eda75fe docs(riir): design inter-module C ABI interfaces and split out oakstorage
- riir.md: split project file read/write into standalone oakstorage
  module (pluggable backend, DB-replaceable); add Mermaid data flow
  diagram of all modules; adjust batch table and milestones
- riir/04-interfaces.md: new provides/consumes contract matrix for
  all modules
- riir/M10-oakstorage.md: new manual with frozen C API (typed opaque
  handles, manual vtable for storage backends, URI addressing)
- riir/01: codify pure-C OO interface rules (typed handles instead of
  void*, init/free pairs, manual vtables, no C++ objects or member
  calls across shared library boundaries); upper layers issue commands
  only, no module-to-module event subscriptions (async task callbacks
  excepted)
- sync 00/02/03 and M2-M9 manuals: remove subscribe APIs, replace
  void* with typed handles, update tests accordingly
2026-08-05 14:48:08 +08:00

78 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 03 · 测试规范(每模块每 C API 必有 Google Test
> 适用于 M1-M9 全部模块。拆分阶段的测试回答一个问题:**经过双层
> 适配器之后,行为和直连 C++ 时一致**。本文冻结测试结构、覆盖要求
> 与 fixture 模式。
## 1. 结构
- 每个模块一个 gtest 二进制:`oak<mod>/tests/`,目标名
`oak<mod>_gtest`,链接 `oak<mod>` + `GTest::gtest` +
`GTest::gtest_main` + QtCore/Gui 按需),经
`gtest_discover_tests()` 注册进 ctest(项目统一约定:Google Test
编写、ctest 运行)。
- 共享 `main.cpp`Qt 初始化照 `tests/gtest/main.cpp` 现有模式
(需要 QApplication 的用 offscreen QPA;纯逻辑的不用建)。
- 需要 engine 全局状态的(EngineCore 单例、ColorManager 配置),
fixture 的 `SetUpTestSuite``oakengine_init(OAKENGINE_INIT_HEADLESS)`
`TearDownTestSuite` 里 shutdown——照 `engine/tests/` 现有惯例。
## 2. 覆盖要求(硬指标)
1. **每个 C API 函数至少 1 个 TEST**。模块手册的 C API 表逐行对应
测试用例;模块完成判据包含一张核对表(M 手册附录,打勾)。
2. 每个函数至少覆盖:**正常路径 1 个** + **错误路径 1 个**
NULL self / 越界索引 / E_INVALID 参数)。
3. **init/free 配对**:每个 init 测试都用泄漏断言收尾(模块级
`oak<mod>_debug_alive_count()` 调试计数器——各模块在 capi 实现里
顺手暴露,测试用它断言"测试前后存活对象数相等")。
4. **枚举序数一致性**:C 侧 POD/枚举与 C++ 侧枚举的映射(01 §3 表)
每个映射 1 个 TEST(如 `oakundo` 的 movement mode 0-3 ⇄
`Timeline::MovementMode`)。
5. **回调(仅异步任务)**:模块间 C ABI 无 subscribe 类接口(04 §3);
仅异步命令(任务/渲染 ticket)的进度/完成回调需要测试:触发后
断言回调被调、payload 正确、FINISHED 后自动失效。同步命令的测试
改为"调用后直接读状态断言生效"。
6. **所有权**:borrowed 句柄(文档注释标了 `/* borrowed */` 的)
free 后原对象仍存活,1 个 TEST。
## 3. 双层往返测试(每个模块至少一套)
证明"消费侧适配类 ⇄ C ABI ⇄ 提供侧实现"全链路与原 C++ 行为一致:
```cpp
class UndoStackRoundtripTest : public ::testing::Test {
protected:
void SetUp() override {
// 提供侧直接 C++ 操作 + 经 C API 操作,对比可观察状态
}
};
TEST_F(UndoStackRoundtripTest, PushPopSymmetry) {
OakUndoStack *h = oakundo_undostack_init(nullptr);
// 经 C API push 两条命令
// 断言 can_undo==1、count==2、jump(0) 后 can_undo==0
// 再经消费侧适配类 olive::UndoStack 包一层做同样操作,断言一致
oakundo_undostack_free(h);
}
```
规则:往返测试操作的是**真实实现**(非 mock);对比点选
"可观察状态"(计数、标志位、文本、事件序列),不比较内部指针。
## 4. 禁止
- 禁止 mock 提供侧实现来"证明"适配层正确(那是自欺欺人)。
- 禁止用 `assert()` 裸断言(项目规则:一律 `EXPECT_*/ASSERT_*`)。
- 禁止测试间共享可变全局状态(每个 TEST 自建对象;单例类资源在
fixture 里清理)。
- GPU/GL 相关用例:沿用 `GTEST_SKIP()` 判定模式(offscreen 不可绘
就跳过,不许靠超时区分)。
## 5. ctest 基线纪律
- 每模块拆完:`ctest -N` 用例数只增不减;新增模块测试全部绿;
既有 45 个不许回归。
- flaky 规则沿用(`oak_cli_transcode`/`oakengine_export_test`/
`olive-gtest` 单独重跑一次,连续两次失败才算回归)。