Skip to content

테스트 인프라

INFO

이 글은 테스트 인프라를 개선하기 위한 아이디어를 나누자는 초대입니다. Discord로 연락 주세요.

Oxc에서는 정확성과 신뢰성을 매우 중요하게 봅니다.

다운스트림 도구로 문제가 퍼지지 않도록 테스트 인프라에 많은 시간을 씁니다.

파서

적합성(Conformance)

Test262, Babel, TypeScript의 파서 테스트로 JavaScript·TypeScript·JSX 문법을 검증합니다.

Test262는 스테이지 4와 정규식 테스트를 모두 포함합니다.

적합성 결과는 스냅샷 파일로 보관해 변경을 추적합니다.

모든 구문 오류도 diff를 위해 이 스냅샷에 기록됩니다.

퍼징(Fuzzing)

파서가 무작위 데이터에서 패닉하지 않도록 세 가지 퍼저를 사용합니다.

  1. 파서에 무작위 바이트를 보내는 cargo fuzz.
  2. bakkotshift-fuzzer-js로 무작위지만 유효한 AST 생성.
  3. qarminAutomated-Fuzzer지속적으로 크래시를 보고합니다.

메모리 안전

Oxc는 AST 등에 bumpalo 기반 아레나 할당자를 씁니다. AST 노드 타입에는 Drop 구현이 없습니다. Oxc 할당자가 컴파일 타임에 아레나에 Drop 타입을 넣으려 하면 오류를 내어 강제합니다. 힙 소유 데이터를 아레나에 두면 누수가 나므로 이렇게 정적으로 막습니다.

unsafe 코드

성능 최적화를 위해 unsafe를 사용합니다. 외부에는 안전한 API만 노출하는 자기완결형 자료구조 안에 unsafe를 가두는 것을 목표로 합니다. Miri는 PR마다 해당 크레이트에 대해 실행됩니다.

린터

진단 스냅샷

모든 린터 진단은 스냅샷 파일에 기록되어 회귀 테스트에 쓰입니다.

예:

javascript
 ⚠ typescript-eslint(adjacent-overload-signatures): All "foo" signatures should be adjacent.
  ╭─[adjacent_overload_signatures.tsx:3:18]
2function foo(s: string);
3function foo(n: number);
  ·                  ───
4type bar = number;
5function foo(sn: string | number) {}
  ·                  ───
6 │       }
  ╰────

Ecosystem CI

oxc-ecosystem-ci는 큰 저장소에 oxlint를 돌려 오탐·회귀·패닉을 확인합니다. 테스트 대상에는 다음이 포함됩니다.

멱등성(Idempotency)

모든 도구에 대해 통합·E2E 테스트에 멱등성 검사를 사용합니다.

멱등성 테스트 절차는 다음과 같습니다.

javascript
let sourceText = "foo";
let printed = tool(sourceText);
let printed2 = tool(printed);
assert(printed == printed2);

예를 들어 코드를 멱등적으로 축약하면 두 번 적용해도 같은 결과가 나와야 합니다.

파서, 변환기, 축약기 등 모든 도구는 Test262·Babel·TypeScript 테스트 파일에 대해 멱등성 검사를 받습니다.

통합 테스트

단위 테스트보다 통합 테스트를 선호합니다.

codecov가 현재 Code Coverage 라인 커버리지를 보고합니다.

E2E

monitor-oxc 저장소는 npm-high-impact 상위 3000개 npm 패키지에 대해 E2E 테스트를 수행합니다.

package.json에는 3000개 의존성이 있습니다.

json
"devDependencies": {
  "@aashutoshrathi/word-wrap": "latest",
  "@actions/http-client": "latest",
  "@adobe/css-tools": "latest",
  "@alloc/quick-lru": "latest",
 ...
  "zip-stream": "latest",
  "zod": "latest",
  "zone.js": "latest",
  "zustand": "latest"
}

이 패키지들을 import하고 import가 성공하는지 검증하는 테스트 파일:

src/dynamic.test.mjs

javascript
import test from "node:test";
import assert from "node:assert";
test("@aashutoshrathi/word-wrap", () => import("@aashutoshrathi/word-wrap").then(assert.ok));
test("@actions/http-client", () => import("@actions/http-client").then(assert.ok));
test("@adobe/css-tools", () => import("@adobe/css-tools").then(assert.ok));
test("@alloc/quick-lru", () => import("@alloc/quick-lru").then(assert.ok));
...
test("zod", () => import("zod").then(assert.ok));
test("zone.js", () => import("zone.js").then(assert.ok));
test("zustand", () => import("zustand").then(assert.ok));
test("zwitch", () => import("zwitch").then(assert.ok));

이 테스트는 코드젠·변환기·축약기 등이 node_modules 전체를 다시 쓴 뒤 실행됩니다.

패키지는 매일 최신 버전으로 갱신됩니다.

이 설정으로 적합성 스위트가 놓친 희귀 버그를 많이 잡았습니다.


테스트 인프라를 어떻게 개선할지 아이디어가 있으면 Discord로 연락 주세요.