跳转到正文

Oracle 测试

Phasis 中的每项实现决策都取决于一个问题:V8 是否会产生相同的输出?

JavaScript 的语义很微妙——NaN !== NaN、-0 === 0、[1] + 1 === "11"、属性枚举的确切顺序,以及 Promise 微任务的时机。通过阅读规范重新推导这些内容既慢又容易出错。Phasis 通过将 Node.js(V8)视为 oracle 来绕开这一问题:编写一个 JS 场景,通过 V8 运行并将输出记录为标准答案;再通过 Phasis 运行一次并再次记录输出;然后比较差异。

代码
1. SETUP    → a JavaScript source file or snippet
2. ORACLE   → Node.js executes it, output captured as truth
3. ACTUAL   → Phasis executes it, output captured
4. COMPARE  → oracle vs actual, diff measures the gap

两个层级的测试

第 1 级 — 自定义场景

scenarios/ 中的每个场景都是一个输出已知的小型 JS 程序。运行单个场景:

命令行
./bin/test-scenario operators/arithmetic

运行全部场景、只运行某个类别,或并行运行:

命令行
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions

刷新 oracle(e.g;在 Node.js 版本更新后):

命令行
./bin/oracle --refresh operators/arithmetic

场景按 ECMAScript 章节分类:字面量、运算符、变量、控制流、函数、对象、数组、类、内置功能、错误、互操作和边缘情况。

第 2 级 — test262

官方 TC39 一致性测试套件以 git 子模块的形式检出到 test262/ 下。每项测试都会自行验证:不抛出异常即通过,抛出异常即失败(negative 测试则相反)。测试运行框架会在每项测试前加载 assert.js 和 sta.js。

命令行
./bin/test262                                    # full suite
./bin/test262 --category built-ins/Array         # subset
./bin/test262 --jobs 4                           # parallel
./bin/test262 --failures                         # one line per failing test
./bin/compat-report                              # full COMPAT.md + compat.json

完整套件快照位于 COMPAT.md,由 bin/compat-report 重新生成。在 CI 中,compat-matrix.yml 工作流会分片运行并提交结果;该工作流需要手动启动,不会在每次推送时运行。

推送前本地检查

./bin/verify-all 会运行 CI 强制执行的质量门禁:

代码
=== PHPStan ===                  level 6, zero errors
=== Code Standards ===           PHPCS, zero warnings
=== PHPUnit ===                  unit suite passes
=== Oracle Regression ===        scenarios under `scenarios/` pass

单独运行还不够——凡是涉及解析器、解释器或内置功能的变更,都必须抽测 test262。每个拉取请求中,CI 都会运行 PHPStan、PHPCS、unit 套件和 oracle 回归测试;拉取请求变更 src/ 或其 fixture 时,才会运行 WPT 和 popular-package 套件。完整的 test262 矩阵不属于拉取请求 CI,因此请在本地抽测受影响的类别。

这样做的原因

将 V8 作为事实依据,几乎可以让开发流程不再需要阅读规范。与 V8 不一致就表示存在 Phasis 错误——绝不是可以争论的规范歧义。修复合并后,相应的 test262 条目就会成为永久回归测试。

100% 的通过率得益于这套规范流程:每个 PR 都依据 V8 进行评估,CI 会拒绝 oracle、WPT 和 popular-package 套件中的回归问题,而运行完整套件时,test262 矩阵会确认其结果。