diff --git a/.gitignore b/.gitignore index e31dddb..d3c2d30 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,5 @@ test_output.txt .coverage case/ *.egg-info/ -.symtest \ No newline at end of file +.symtest +.venv/ \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in index bf2f3b9..ef39e29 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ include README.md include LICENSE recursive-include docs * -recursive-include tests * \ No newline at end of file +recursive-include skill * +recursive-include tests * \ No newline at end of file diff --git a/README.md b/README.md index a91fa20..12fce49 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ one JSON or YAML configuration: - **Verify results** — return codes, output text and regular expressions, plus text, JSON, CSV, XML, HDF5, binary, and custom-script file comparisons. - **Manage large suites** — split configurations with `import`, reuse templates - with `extends`, filter by name or tag, and inspect cases across files in the - optional TUI. + with `extends`, filter by name or tag, and locate cases across files with + `symtest find`. - **Iterate and integrate** — parallel execution, `--last-failed`, step-level `--resume`, runtime history, structured reports, and JUnit XML output. @@ -46,11 +46,10 @@ Python 3.9 or newer is required. pip install symtest-cli ``` -YAML and the TUI are optional: +YAML support is optional: ```bash pip install "symtest-cli[yaml]" -pip install "symtest-cli[tui]" pip install "symtest-cli[all]" ``` @@ -155,7 +154,7 @@ symtest run solver_tests.json -t long_case --resume `--resume` deliberately trusts that workspace artifacts have not changed between runs. -## Large test suites and the optional TUI +## Large test suites and cross-file search Large suites can be divided into sub-configurations: @@ -168,12 +167,12 @@ Large suites can be divided into sub-configurations: } ``` -The optional TUI provides one searchable view across imported files. It is -intended as an aid for locating cases and reviewing scenario coverage in large -projects, rather than a requirement for normal test execution. +`symtest find` auto-expands all `import` references and searches across the +unified case set (substring / fuzzy / regex modes), making it easy to locate +cases and review scenario coverage in large projects: ```bash -symtest tui main_config.json +symtest find main_config.json "login" ``` ## Parallel execution and resources @@ -249,9 +248,9 @@ requirement for using the framework. - [User manual](docs/user_manual_en.md) - [Design document](docs/design_en.md) - [Plugin examples](examples/plugins/README.md) -- [AI Skill template](examples/skill/) — import framework knowledge into AI coding - assistants so they can author test cases, acceptance criteria, - and TDD workflows directly +- [Official AI Skill](skill/) — install this skill into AI coding assistants + so they can author test cases, acceptance criteria, and TDD workflows + directly — the recommended entry point for new users ## Development diff --git a/README_cn.md b/README_cn.md index 7243519..6200dec 100644 --- a/README_cn.md +++ b/README_cn.md @@ -25,7 +25,7 @@ CLI Test Framework 使用一份 JSON 或 YAML 配置,同时描述执行流程 - **验证结果**:支持返回码、输出文本、正则表达式,以及 text、JSON、CSV、XML、 HDF5、二进制和自定义脚本文件比较。 - **管理大型测试集**:通过 `import` 拆分配置、通过 `extends` 复用模板、按名称或 - 标签筛选,并可在可选 TUI 中跨文件查看用例。 + 标签筛选,并可用 `symtest find` 跨文件定位用例。 - **迭代与集成**:支持并行执行、`--last-failed`、步骤级 `--resume`、耗时历史、 结构化报告和 JUnit XML。 @@ -39,11 +39,10 @@ CLI Test Framework 使用一份 JSON 或 YAML 配置,同时描述执行流程 pip install symtest-cli ``` -YAML 和 TUI 均为可选能力: +YAML 为可选能力: ```bash pip install "symtest-cli[yaml]" -pip install "symtest-cli[tui]" pip install "symtest-cli[all]" ``` @@ -143,7 +142,7 @@ symtest run solver_tests.json -t long_case --resume `--resume` 明确信任两次运行之间的工作区产物未被修改。 -## 大型测试集与可选 TUI +## 大型测试集与跨文件搜索 大型测试集可以拆分为多个子配置: @@ -156,11 +155,11 @@ symtest run solver_tests.json -t long_case --resume } ``` -可选 TUI 能在所有导入文件之上提供统一的可搜索视图,主要用于大型项目中定位用例和 -辅助检查场景覆盖情况,并不是日常执行测试的必要组件。 +`symtest find` 会自动展开全部 `import` 引用,在统一展开后的用例集上执行搜索 +(子串 / 模糊 / 正则三种模式),便于大型项目中定位用例和检查场景覆盖: ```bash -symtest tui main_config.json +symtest find main_config.json "login" ``` ## 并行执行与资源 @@ -232,7 +231,7 @@ compare-files data1.json data2.json --json-compare-mode key-based --json-key-fie - [中文使用说明](docs/user_manual.md) - [中文设计文档](docs/design.md) - [插件示例](examples/plugins/README.md) -- [AI Skill 模板](examples/skill/) — 可将框架知识导入 AI 编程助手, +- [官方 AI Skill](skill/) — 可将框架知识导入 AI 编程助手(推荐的入门方式), 让 AI 直接使用框架编写测试用例、验收标准和 TDD 工作流 ## 开发 diff --git a/docs/design.md b/docs/design.md index 2bf9b0e..773c533 100644 --- a/docs/design.md +++ b/docs/design.md @@ -10,8 +10,8 @@ ``` ┌─────────────────────────────────────────────────────────────┐ -│ CLI 入口层 symtest run / tui / validate / schema / │ -│ compare-files(+ TUI 交互界面) │ +│ CLI 入口层 symtest run / find / validate / schema / │ +│ compare-files │ └───────────────────────────┬─────────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ @@ -32,7 +32,7 @@ └─────────────────────────────────────────────────────────────┘ ``` -框架分为四层:**CLI 入口层**(含 TUI)、**Runner / Comparator 业务层**、**Config 管线层**、**Core 基础层**。 +框架分为四层:**CLI 入口层**、**Runner / Comparator 业务层**、**Config 管线层**、**Core 基础层**。 层与层不是自由组合:跨层数据流与依赖方向受 §10「核心架构宪法」约束, 新增 feature 请先对照宪法确定归属。 @@ -49,14 +49,13 @@ | `runners/` | Config/JSON/YAML × 顺序/并行 的薄封装运行器 | | `file_comparator/` | 比较器家族 + 工厂 + workspace 插件发现(详见 §6) | | `utils/` | 路径解析、报告生成、JUnit XML 输出 | -| `tui/` | Textual 交互式用例管理(详见 §7) | ### 2.1 入口点 | 命令 | 映射 | |---|---| | `symtest run` | `symtest.cli:run_tests` | -| `symtest tui` | `symtest.tui.app:run_tui` | +| `symtest find` | `symtest.commands.find:run_find` | | `symtest validate` | `symtest.cli:run_validate` | | `symtest schema` | `symtest.cli:run_schema` | | `symtest compare` | `symtest.cli:run_compare` | @@ -155,14 +154,11 @@ PathResolver 解析(系统命令直通、shell builtin 平台包装、复合 → 超时 kill 整个进程组 → 返回附带 `next_action_hint` 的结构化结果。 -当前实现的上述行为仍聚合在一处;1.4 将按 §10 宪法重排为 -Executor / Validator / Orchestration 三段(迁移明细见 docs/design_1_4.md)。 - ### 4.6 断言与文件比较集成 - `compare_files` 是一等断言,经 ComparatorFactory 按类型分发(详见 §6) - 所有断言可选;未声明的字段不做校验 -- `--error-analysis` 为 CSV/H5 数值比较提供流式误差统计:`total_numeric_cells` / `mismatched_cells` / `max_abs_error` / `max_rel_error` / `mean_abs_error` / `rms_abs_error` +- `--error-analysis` 为 CSV/H5 数值比较提供流式误差统计:`total_numeric_cells` / `mismatched_cells` / `max_abs_error` / `max_rel_error` / `mean_abs_error` / `rms_abs_error`;幅值统计(max/mean/rms)覆盖全体参与比较的数值单元格(含通过格),mean/rms 以 `total_numeric_cells` 为分母。`--error-analysis-all` 额外对通过用例输出统计,除此之外两者行为一致 ## 5. 运行时状态持久化(`.symtest/`) @@ -178,33 +174,68 @@ Executor / Validator / Orchestration 三段(迁移明细见 docs/design_1_4.md ## 6. 文件比较子系统 -### 6.1 比较器分层 +### 6.1 三泳道比较器架构 + +所有比较器共享根契约 `ComparatorBase.compare(ctx) -> ComparisonResult`: +框架构建 `CompareContext`(workspace / actual / baseline / params / error_analysis); +`actual`/`baseline` 以及插件 `path_params` 声明的构造参数在**比较器构造之前** +按 workspace 统一解析,插件不得自行对 CWD resolve。配置单一事实源: +比较器配置只存在于构造器捕获的实例状态,`ctx` 仅承载调用级上下文。 +三条泳道职责互斥: + +| 泳道 | 基类 | 契约 | verdict 归属 | 内置实例 | +|---|---|---|---|---| +| 文件泳道 | `FileComparator` | `read_content` + `compare_content`(两文件模型,行列窗口、line N 偏移、chunk_size、similarity 均属本泳道) | 插件 | text / json / csv / xml / h5 / binary | +| 数据泳道 | `ExtractorComparator` | `extract(ctx) -> {channel: ChannelData}`;框架逐通道跑 `compare_numeric`,per-channel 容差(`channels` / `default_channel`),聚合 `ChannelResult` | **框架**(容差语义对 AI 消费端可预期) | script_extract、extractor 插件 | +| 自主泳道 | 直接继承根 | `compare(ctx)` 全权判定 | 插件 | script、hourglass 式分析插件 | + +- 文本系共享 difflib 行级基底,json / csv / xml 为其结构化特化;h5 面向科学数据集;binary 流式分块 + LCS 相似度 +- 统一返回 `ComparisonResult`(identical / differences / error / error_stats / command_output / channels),支持 text / json / html 渲染 +- 数据泳道插件可通过 `ChannelData.extra_stats` 附带自定义误差指标,存放在独立命名空间(`ChannelResult.extra_stats`),不可覆盖框架规范指标;但 verdict 仍由框架容差持有——需要自定 verdict 的走自主泳道 -- 文本系比较器共享 difflib 行级基底,json / csv / xml 为其结构化特化(键对齐 / 列结构 / DOM 对齐) -- h5 面向科学数据集;binary 流式分块 + LCS 相似度;script 委托外部脚本 -- 统一返回 ComparisonResult(identical / differences / error / script command_output),支持 text / json / html 渲染;支持行列窗口范围参数截取后比较 +### 6.2 通道协议(数据泳道) + +- 通道判定:`identical = all(channels.passed)`;差异 position 带通道前缀(`channel S33`);`error_stats` 按通道名嵌套 +- 内置 `script_extract` 类型:子进程执行用户脚本(零改动接入),脚本 stdout 输出约定 JSON: + +```json +{"channels": {"S11": {"expected": [...], "actual": [...], "extra_stats": {...}}}} +``` -### 6.2 工厂与插件发现 + 非零退出、超时、畸形 JSON 一律判为比较 error(绝不静默通过);`actual`/`baseline` 按惯例以 baseline 在前的顺序追加为尾部 argv 槽位(可缺省) +- 结果粒度:一条 compareSpec = 一条断言;`ComparisonResult.channels` 携带通道级子结果,报告逐通道展示 pass/fail + stats;JSON 输出中通道 differences 按 per-channel 配额截断 -- `file_type` 取值:`text` / `json` / `csv` / `xml` / `h5` / `binary` / `script`;工厂按类型分发,支持动态注册与全局 reset(测试用) -- 插件发现四处来源:内置 `*_comparator.py` 自动发现、`workspace/comparators/` 自动扫描、`--plugin-dir` CLI 参数、`CLITEST_PLUGIN_DIRS` 环境变量(供进程模式 worker 使用) -- 命名约定:`*_comparator.py` + `*Comparator` 类名 +### 6.3 工厂与插件发现 -### 6.3 script 比较协议(对外契约) +- `file_type` 取值:`text` / `json` / `csv` / `xml` / `h5` / `binary` / `script` / `script_extract`;工厂按类型分发,支持动态注册与全局 reset(测试用) +- 插件发现四处来源:内置 `*_comparator.py` 自动发现、`workspace/comparators/` 自动扫描、`--plugin-dir` CLI 参数、`CLITEST_PLUGIN_DIRS` 环境变量(用户声明的输入;框架只读,进程模式 worker 经进程池 initializer 显式接收插件目录,框架从不修改 `os.environ`) +- 命名约定:`*_comparator.py` + `*Comparator` 类名;可用类属性 `comparator_type` 显式指定类型名(如 `script_extract`);抽象基类自动跳过注册 +- 配置传递与严格校验:`actual`/`baseline`/`type`/`options` 之外的键转发给比较器构造函数(kwargs);构造器参数是**严格**的——未声明的键(拼写错误)在构造时大声失败并给出支持参数清单。`options` 是框架持有的插件配置命名空间(并入构造参数,显式顶层键优先),核心 schema 不为单个插件增加专属字段;`channels`/`default_channel` 属数据泳道框架结构 -- 子进程方式执行 `