# @adlc/hollow-test 中文文档

规范地址：https://npmcn.com/package/%40adlc/hollow-test/

版本：1\.12\.0
npm 元数据更新时间：2026-10-10T03:03:38.987Z
中文译文更新时间：2026-11-06T00:27:03.883Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40adlc/hollow-test
原文对照：https://npmcn.com/package/%40adlc/hollow-test/?lang=original
项目主页：https://github.com/voodootikigod/adlc/tree/main/packages/hollow-test#readme
源码仓库：https://github.com/voodootikigod/adlc

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：141 kB，11 个文件
- 模块格式：ES Module
- TypeScript 类型：未声明
- Node.js 要求：\>=18
- 运行依赖：1 个
- 首次发布：2026-06-13T21:12:24.657Z
- 最新版本发布：2026-10-10T03:03:38.685Z
- 近 30 天下载量：8199（2026-10-05 至 2026-11-03，npm 官方下载统计）
- 已发布版本数：18（近 12 个月 18 个）

## 中文简介

Diff-scoped突变门-诚实覆盖检查,只变换行(P3/C4).

## 安装

```sh
npm install @adlc/hollow-test
```

也可以使用：`pnpm add @adlc/hollow-test`、`yarn add @adlc/hollow-test`、`bun add @adlc/hollow-test`

## README

# 空心测试

**ADLC相:P3出入口(C4-diff-scoped surfion) 出入口:**

Diff-scoped突变门-诚实封面检查. 只变换行 在您的 diff 中更改了, 运行您的测试套件对每个变种人, 如果失败 任何变异都会活下来 幸存的变种人证明了空洞的覆盖: 但他们的行为不受任何断言的约束.

Diff - scroping 将运行时间控制在秒到分之间,而不是时间 杀死全码基突变测试.

## 使用量

```
hollow-test --test-cmd "node --test test/" [options]
```

### 旗帜

| 旗帜 | 默认 | 说明 |
| --- | --- | --- |
| `--test-cmd <cmd>` | _(必须)_ | 壳牌命令运行测试套房. 失败时必须离开非零. |
| `--base <ref>` | `HEAD` | Git Base ref for the diff (例如:. `HEAD~1`, (中文(简体) ), `main`一个SHA. |
| `--max <n>` | `20` | 所有文件的最大总变种人 。 预算是分散的循环循环. |
| `--timeout-ms <n>` | `120000` | 一次性测试命令超时, 以毫秒计 . |
| `--target <file>` | _(无)_ | 直接改变此文件, 独立于 diff( repeatable) 。 绕过测试/ spec路径排除,并变换整个文件,而不仅仅是diff-changed行. |
| `--rails <ticket-file>` | _(无)_ | 一张JSON票文件的路径;其已申报 `rails` 缩写比对 `git ls-files` 并添加为突变目标(可重复). |
| `--json` | _(关闭)_ | 机器可读JSON输出(用于管弦乐手). |
| `--help` | _(关闭)_ | 显示使用和退出 0. |

### 退出代码

| 代码 | 含义 |
| --- | --- |
| `0` | 出道口——所有变种人被杀死. |
| `1` | 操作错误 — 肮脏的工作树, 不是 git repo, 糟糕的论点, **无可突变** (diff中没有符合条件的源文件,也没有 `--target` 也没有 `--rails` ),或a **所选文件没有收到突变预算** (见下文). |
| `2` | 门故障——一名或多名变种人幸存(霍洛覆盖). |

### `--max` 对 diff 来说太小: 已饿死的文件无法关闭

`--max` 将变种预算圆旋边分布到每个选定的文件,并小 `--max` 对宽的diff可以留下一个或多个diff衍生文件 **零配额** —— 说 从未变异过 那文件的更改代码 之后没有验证,所以 `hollow-test` 拒绝 以报告通行证:它退出 `1` 并列出每个被饿死的文件 而不是沉默 传递其他文件 得到的预算。 提升 `--max` 覆盖所选文件 (每个文件至少更改一个),或缩小diff:

```bash
$ hollow-test --test-cmd "node --test test/*.test.mjs" --base HEAD~1 --max 1
error: 2 selected file(s) received no mutation budget and were NOT prosecuted: src/b.mjs, src/c.mjs — raise --max to cover them.
```

这不适用于收到预算但没有可变行的文件(a) ——这个案件仍然只是警告,因为文件是真实的 而不是因为预算不足而跳过.

### `--target` 编号 : `--rails`: P3 铁路授权/特征测试

添加一个 diff **只测试文件** ——正是P3铁路的造型,或者 一种特征测试票,将现有的、不变的(冷冻-铁路)行为钉住——有 没有 `filterTargetFiles()`'diff 范围可变. 而不是默默报告 空闲 `0`编号 :`0`编号 :`0` 通行证, `hollow-test` 输出 `1` 在这种情况下,除非给出明确的目标:

```bash
# Diff is test-only (new rails for src/foo.mjs, which itself didn't change) — mutate
# src/foo.mjs directly so the new rails are actually prosecuted:
hollow-test --test-cmd "node --test test/foo-rails.test.mjs" --base main \
  --target src/foo.mjs

# Same, but read the target from a ticket's declared "rails" (single-ticket object or a
# full tickets.json — rails merged across all tickets in the file):
hollow-test --test-cmd "node --test test/foo-rails.test.mjs" --base main \
  --rails .adlc/tickets.json
```

## 实例

```bash
# Check the last commit
hollow-test --test-cmd "node --test test/" --base HEAD~1

# Check staged changes vs main
hollow-test --test-cmd "npm test" --base main --max 30

# Machine-readable output for CI
hollow-test --test-cmd "node --test test/*.test.mjs" --json
```

## 安全保障

1.  **肮脏的树木检查**: 如果 `git status --porcelain` 不为空. 这样可以防止不小心离开损坏的文件, 如果进程是 中断 。 先提交或保存您的更改 .
    
2.  **文件恢复**: 每个变异文件通过 a 恢复 `try/finally` 块 - 即使测试命令崩溃或进程通过 签字。 SIGINT 处理器在退出前进行紧急恢复.
    
3.  **顺序处决**: 变种人一次应用并测试一次 (绝不平行)避免同时写到同一个文件.
    
4.  **绿色基线**:在变异前需要绿色基线,所以失败的套房不能伪装成杀死每一个变异者. 如果基线套件失败,空心测试会在出站前将测试命令所捕获的stdout和stderr释放出stderr,确保失败原因和失败测试是可诊断的.
    
5.  **暂停结束所有开始的套房**:每次审判都经过一个 小型看管儿童(`lib/watchdog.mjs`保持套房在你自己的 过程组和会话,在超时起火时,冻结被害者(SIGSTOP,向外取根,重新收起) 直到稳定,所以在杀戮期间叉子不能因为被再生而滑出) 然后用SIGKILLLL他们。 受害者是贝壳的活生生的后代 加上,在 Linux, 环境仍然带有外壳标记的每个进程 开始于(链条,所以一个有巢穴的空心测试 延伸它而不是) 把它的树树藏在外边,它抓住一个帮手 更早的审判中双叉或脱去. 任何结束于 外壳本身在空心测试的stderr上随其发生而命名(并折叠成 所以,一个守护进程 套件的脱落不是 无声地消失 父链接来自 `/proc` 在没有分叉的Linux上, 因此,这个在它存在的内存- 渴望的主机上工作; 其他平台使用 时间框 `ps` 只有活树, 监督者也会投票给父母: 如果空洞试验本身被彻底地杀死`kill -9`来电暂停,它 结束了套房和出入口 而不是被困在这里。 同样的扫荡 在 Ctrl- C 上运行( 弹壳启动) `&` 包含 SIGINT 的作业被忽略, 因此是一个助手 开始于 `server & npm test` 以及任何时间 壳单出,所以坠毁 `node --test` 不能拖着工人 超过超时(在路径上,贝壳已经收割,所以) 只有标记扫描仍然可以命名它留下的东西,在Linux上). 还有什么 逃出:一个在解开后清洗自身环境的过程,以及一个 无法读取的平台上的解开助手 `/proc`在这一切之前, `node --test`它的档案工作者和任何 套房产出的生命 作为孤儿的每一个定时变种人 仍然执行变种密码 一堆 他们把一个主机 下来(2026-10-08): RAM和互换 满了,没有杀死,SSH 登录从未获得外壳). Windows运行未被封存的命令 .
    
6.  **每个节点都有一个V8高盖**: 测试命令开始的每个节点都得到 `--max-old-space-size` 通过 `NODE_OPTIONS` (默认2048 MiB,由 使得JS-heap生长不受限制 死后用"堆积出内存"而不是运行到超时. 这是一个 每个进程绑在一个隔离器的旧空间上,而不是一个主机绑定 : `node --test` 并行运行文件, 缓冲、 缓冲缓冲和本地内存在外 它(2026-10-08出逃是一股无尽的"缓冲"). 锁定主机 有组( c)`systemd-run --scope -p MemoryMax=…`; 依赖担保 5 到 结束一个逃跑. `HOLLOW_TEST_MAX_OLD_SPACE_MB=<n>` 更改上限; `0` 禁用 它; 当变量未被设定时, a `--max-old-space-size` (或 `--max_old_space_size`你已经放进去了 `NODE_OPTIONS` 保存; 设置时,它取代任何被继承的旗帜。 基线运行使用相同的设置,所以一个真正需要的套房 更响亮的失败在那里,不是沉默的中门, 和标本它打印的名字 盖和变量。 默认值低于节点本身的大型默认值 主机; 需要更多设置变量的套件 .
    

## 哪些变异( 哪些被跳过)

突变仅适用于平版 JavaScript : `.mjs`, (中文(简体) ), `.cjs`, (中文(简体) ), `.js`。这是一个 **允许列表**. TypeScript和JSX (中文(简体) )`.ts`, (中文(简体) ), `.mts`, (中文(简体) ), `.cts`, (中文(简体) ), `.tsx`, (中文(简体) ), `.jsx`, (中文(简体) ), Python, CSS 和其他一切都排除在外, 因为操作员是 基于文本且无法从类型参数或JSX中分辨比较 分隔器 - `Promise<unknown>` 变成无效 `Promise>=unknown>`,则a 解析失败目前被评为 a _被杀死_ 变种人. 参见第293期.

路径时文件也会被跳过 **部分** 实值 `test`, (中文(简体) ), `tests`, (中文(简体) ), `spec`, (中文(简体) ), `specs`,或 `__tests__`,或何时 **碱性名称** 匹配一个 `node --test` 发现公约: `test.js`, (中文(简体) ), `test-*`, (中文(简体) ), `test_*`, (中文(简体) ), `*-test.*`, (中文(简体) ), `*_test.*`, (中文(简体) ), `*.test.*` (和 `spec` (见a/c.5/49/70,附件).

匹配是局部和基名故意的: 次弦测试会 排除生产途径,例如: `packages/hollow-test/lib/targets.mjs` 或者说 `lib/attest.mjs`。 。 。 .

两个逃出舱门, 因为没有公约解决每一个案件:

-   `--test-glob <glob>` - 将其他路径作为测试.
-   `--source-glob <glob>` - 将路径当作生产来源,即使它们的名称 符合试验公约。 需要产品名称,如 `hollow-test.mjs` 财务报告和审定财务报表 `spec-lint.mjs`,仅通过命名就无法与测试区分. 出于同样的原因, **连字符** 表单( 表格)`foo-test.js`, (中文(简体) ), `spec-foo.js`已经 _没有_ 作为测试处理——测试之间的连字符模糊不清 公约和产品名称,以及 `hollow-test.mjs` 财务报告和审定财务报表 `spec-lint.mjs` 为: 生产文件。 如果你用那条公约, 保持测试在一个 `test/` 目录 或命名他们 `*.test.*`。 。 。 . `--target`编号 :`--rails` 文件绕过 **测试路径** 排除——呼叫者是 故意给突变目标取名,而铁路通常是测试文件.

没错 **没有** 绕过语言允许列表。 操作员为JS/TS形,以及 使另一种语言在战术上无效的变异者进行测试 命令退出非零,该数值为 _被杀死_ 假的通行证 所以说:

-   `--target <path>` 在不支持的语言中 **拒绝** (出处1). 这个 呼叫者给一个文件取了名字;默默地放弃它将是它自己的无声通道.
-   `--rails <ticket>` 扩展合法匹配非源( e)`schemas/**`, (中文(简体) ), JSON,固定装置)。 这些被过滤出来 **报告**运行失败 只有在没有变异物存在的情况下.

在 diff 衍生的合格文件中, 仅 diff 中更改的行是 目标; `--target`编号 :`--rails` 文件全部变异。 线条 空白、评论、进口、, `export {`,或 `console.*` 电话被跳过.

### 仅报告评论的更改为未涵盖

更改后的文件, 其程序没有被更改—— 只有注释或空白 添加、重写或去除行——没有可变行为。 它没有失败;它 在 stdout 上列出未覆盖,当它是唯一的更改时,运行出口 `0` 与 `comment-only diff — no changed behaviour to mutate`与 `--json` 页:1 同一文件出现在 `"skipped": { "commentOnly": [...] }`,在早期退出时 和正常报告一样.

双侧的diff 被判断,所以这些是 **没有** 仅批注并留下 变异目标(在无可变残骸时关闭):

-   已删除并被注释或空白行所取代的代码行;
-   以添加方式包裹的活代码 `/*` . `*/`· ;
-   删除 `*/` 将后面的代码变为注释文本;
-   (单位:千美元) `// ...` 在多行模板文字内行,这是字符串数据.

任何疑义 — 一个无法读取的文件, 一个无法读取的旧面 `--base`页:1 扫描丢失其位置——保持文件目标.

### 无效的变种人

生成代码节点无法解析的突变是 **丢弃**没有得分. 基于线路的运营商定期生产这些产品—— `null-return` 重写 a 多线 `return {` 改为 `return null;` 并绑起对象的文字 剩余行.

这很重要 因为一个杀手是从一个非零出口 和一个文件推断出来的 不分析同时退出非零。 计算这样的变种人 _被杀死_ 伪造 覆盖; 计为 _幸存下来_ 将从未有过的代码归咎于测试 无效。 报告本身 `invalid` 在桌子和JSON两个都装入桶子.

若为 **每个** 运行中的变异是无效的, 空洞的测试出口 **1个** (业务 而不是通过:没有行使任何断言,因此运行证明 没什么.

审定用途 `node --check`,所以不添加解析器依赖度和真实 文件扩展名和软件包类型都得到了遵守。 语法检查和测试都是 **三态** —— 说 `valid`, (中文(简体) ), `invalid`,或 `unknown`."可能不会 确定“ 永远不会崩溃为“ 有效 ” : 如果检查器被杀死, 时间已过期, 或 不能产卵,运行失败 操作而不是猜测。 测试命令本身也是如此:产卵故障(EAGAIN, ENOMEM)不是超时,超时是唯一算作杀活的未完成. 杀死一定意味着测试失败了 假设 有效性将运行测试命令以对抗无法解析的源,其非零 退出后被评为杀出——这一关上的道路.

完全无效的警卫被应用 **每个文件**不只是全球范围 全球检查 任何其它文件一旦失效 就会被明确允许 名称 `--target` 运行报告成功时完全没有测试.

### 变异运算符(来自 `@adlc/core`(中文(简体) )

| 运算符 | 示例 |
| --- | --- |
| `invert-comparison` | `===` → `!==`, (中文(简体) ), `<=` → `>` |
| `bool-flip` | `true` → `false` |
| `null-return` | `return expr` → `return null` |
| `off-by-one` | 字义 `n` → `n+1` |
| `logic-swap` | `&&` → `||` |

**`off-by-one` 不改变调制常数.** `+1` 期限 毫秒或以字节表示的大小是一个 _等同变异者_ - 任何测试都无法观察 `60000 -> 60001` 在子进程超时时数上 ms- 因此生成需要测试 这不可能存在(# 359)。 规则读取常数 **名称**,拆分为 部分,以及 `snake_case`编号 :`camelCase` 拼写相同 :

| 名称 | 变异? | 为什么 |
| --- | --- | --- |
| `GIT_TIMEOUT_MS`, (中文(简体) ), `maxBufferBytes`, (中文(简体) ), `TTL_MS` | 没有 | 次秒/ 字节 **单位** - 不可观察的规模 |
| `timeout`, (中文(简体) ), `ttl`, (中文(简体) ), `maxBuffer`, (中文(简体) ), `highWaterMark` | 没有 | 已知调音符 **语句** |
| `MAX_RETRIES`, (中文(简体) ), `retryLimit`, (中文(简体) ), `chunkSize`, (中文(简体) ), `timeoutRetries` | **对** | 跟踪 **计数** 字词——一个可计数的边界,不管名字上写了什么 |
| `RETENTION_DAYS`, (中文(简体) ), `GRACE_HOURS` | **对** | 粗糙的时间单位 _实值_ 在注入的时钟下可观察到 |
| `{ ttl: 0 }`, (中文(简体) ), `{ timeout: -1 }` | **对** | `0`/负是离散的哨兵,而不是星等 |

后面的数字总是胜过名字中的调音短语,所以 扩大短语列表,永远不能默默地删除对一个伯爵的起诉. 命名 单位是获得面具的人 `MAX_BUFFER_SIZE_BYTES` 被蒙上阴影 `MAX_BUFFER_SIZE` 没有(# 372). | `negate-guard-subclause` | `Array.isArray(x)` ↔ `!Array.isArray(x)`· ; `if (value)` → `if (!value)`; 松开 `v == null` ↔ `v != null` | | `array-literal-shrink` | `['id', 'title', 'scope']` → `['id', 'title']` | | `ternary-swap` | `cond ? a : b` → `cond ? b : a` |

## JSON 输出计划

```json
{
  "tool": "hollow-test",
  "summary": {
    "total": 5,
    "killed": 4,
    "survived": 1
  },
  "mutants": [
    {
      "file": "src/calc.mjs",
      "line": 7,
      "operator": "null-return",
      "status": "survived",
      "timedOut": false,
      "original": "  return a + b;",
      "mutated": "  return null;"
    }
  ],
  "skipped": { "commentOnly": ["src/notes.mjs"] }
}
```

`skipped` 仅当更改的文件被保留为仅作为注释时才会存在.

## 与兄弟姐妹工具的关系

-   **护栏(C5)**: 执行在构建过程中不修改测试文件 (它们是测量仪器) 空心测试验证这些测试 实际限制行为.
-   **审查-校准(C8)**: 使用同样的 `mutate` 植入错误的操作员 并量检校者的记忆。 空心测试和审查-校准共享核心 变相机械.
-   **闪光探测器(C6)**:空心测试为P3门;花纹探测器手表 p4构建会议。 它们服务于补充阶段.

## 核心差距

无。 所有需要的功能(`gitDiff`, (中文(简体) ), `isDirty`, (中文(简体) ), `isGitRepo`, (中文(简体) ), `git`, (中文(简体) ), `globMatch`, (中文(简体) ), `mutate.generateMutants`, (中文(简体) ), `mutate.applyMutant`, (中文(简体) ), `mutate.changedLinesFromDiff`, (中文(简体) ), `parseArgs`, (中文(简体) ), `pass`, (中文(简体) ), `gateFail`, (中文(简体) ), `opError`, (中文(简体) ), `printJson`) 可在 `@adlc/core`。 。 。 .

## 执行说明

### NODE TEST CONTEXT 剥离

节点.js v22 sets `NODE_TEST_CONTEXT` 在儿童过程环境中 运行在下 `node --test`。如果一个程序继承了该变量和 本身称谓 `node --test`,它默默地跳过所有测试文件(exits 0). 空心试验条 `NODE_TEST_CONTEXT` 儿童环境的影响 运行每个变种人的测试命令。 这确保了突变审判工作 即使空心测试本身在测试带内运行 也是正确的.

## 常见问题

### @adlc/hollow-test 是什么？

Diff-scoped突变门-诚实覆盖检查,只变换行\(P3/C4\)\.

### 如何安装 @adlc/hollow-test？

在项目目录运行 npm install @adlc/hollow-test，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 hollow-test，可以用 npx hollow-test 直接运行。

### @adlc/hollow-test 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/adlc\_\_hollow-test 是否存在。

### @adlc/hollow-test 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @adlc/hollow-test 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @adlc/hollow-test 可以商用吗？

@adlc/hollow-test 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @adlc/hollow-test 的下载量有多少？

根据 npm 官方下载统计，@adlc/hollow-test 在 2026/10/05 – 2026/11/03 这 30 天内被下载 8,199 次，日均约 273 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @adlc/hollow-test 还在维护吗？

最新版本 1\.12\.0 发布于 2026/10/10（27 天前）；至今共发布 18 个版本，其中过去 12 个月发布了 18 个；首次发布于 2026/06/14。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

