테스트 인프라
INFO
이 문서는 우리 테스트 인프라를 개선하기 위한 아이디어 공유를 초대하는 글입니다.
디스코드에서 언제든지 저희와 연락하시기 바랍니다.
Oxc에서는 정확성과 신뢰성에 매우 큰 주의를 기울입니다.
하위 도구로 문제가 전파되지 않도록 하기 위해, 우리는 테스트 인프라 강화에 많은 시간을 할애합니다.
파서
일관성 검증
테스트262, Babel, TypeScript의 파서 테스트는 자바스크립트, 타입스크립트, JSX 문법을 테스트하는 데 사용됩니다.
테스트262의 경우, 모든 스테이지 4 및 정규 표현식 테스트가 포함됩니다.
모든 일관성 검증 결과는 변경 사항을 추적하기 위해 스냅샷 파일에 저장됩니다:
모든 구문 오류는 이러한 스냅샷 파일에 기록되어 변경 사항을 비교할 수 있습니다.
퍼즈 테스트
랜덤한 데이터에 직면했을 때 파서가 충돌하지 않도록 보장하기 위해 세 가지 퍼즈 툴이 사용됩니다:
- cargo fuzz는 파서에 랜덤 바이트를 보내는 용도로 사용됩니다.
- bakkot이 만든 shift-fuzzer-js는 랜덤하지만 유효한 AST를 생성합니다.
- qarmin이 만든 Automated-Fuzzer는 활발하게 충돌 보고를 수행합니다.
메모리 안전성
Oxc는 AST 및 기타 데이터를 위한 메모리 할당자로 bumpalo 기반의 아레나 할당자를 사용합니다.AST 노드 유형 중 어떤 것도 Drop 구현을 갖고 있지 않습니다.
이는 Oxc의 할당자가 컴파일 시점에 이를 강제하며, 아레나에서 Drop을 가진 타입을 할당하려는 코드가 있다면 컴파일 에러를 발생시킵니다.
이는 힙에 할당된 데이터를 소유하는 타입이 아레나에 저장될 수 없음을 정적 방식으로 보장하여 메모리 누수를 막습니다.
비안전 코드
성능 최적화를 위해 Oxc는 unsafe 코드를 사용합니다. 우리는 unsafe를 외부에서 안전한 인터페이스를 제공하는 자체적으로 분리된 데이터 구조 내부로 제한하고자 합니다. 이러한 구조를 포함하는 크레이트들에 대해 매번 프로젝트 요청(또는 PR)마다 Miri가 실행됩니다.
리터
스냅샷 진단
모든 리터 진단은 스냅샷 파일에 기록되어 회귀를 테스트할 수 있도록 합니다.
예시:
⚠ typescript-eslint(adjacent-overload-signatures): "foo" 서명은 모두 인접해야 합니다.
╭─[adjacent_overload_signatures.tsx:3:18]
2 │ function foo(s: string);
3 │ function foo(n: number);
· ───
4 │ type bar = number;
5 │ function foo(sn: string | number) {}
· ───
6 │ }
╰────생태계 CI
oxc-ecosystem-ci는 큰 저장소들에 oxlint를 적용하여 잘못된 경고, 회귀 및 충돌 여부를 확인합니다. 테스트 대상 저장소는 다음과 같습니다:
- rolldown/rolldown
- napi-rs/napi-rs
- toeverything/affine
- preactjs/preact
- microsoft/vscode
- bbc/simorgh
- elastic/kibana
- DefinitelyTyped/DefinitelyTyped
동일성 검증 (Idempotency)
동일성 검증 테스트는 모든 도구의 통합 테스트 및 엔드투엔드 테스트에 사용됩니다.
동일성 검증 테스트는 다음과 같은 절차를 따릅니다:
let sourceText = "foo";
let printed = tool(sourceText);
let printed2 = tool(printed);
assert(printed == printed2);예를 들어, 코드를 동일하게 최소화하면 같은 결과가 나와야 합니다.
모든 도구(파서, 변환기, 최소화기 등)는 테스트262, Babel 및 TypeScript 테스트 파일에서 동일성 검증 테스트를 수행합니다.
통합 테스트
통합 테스트는 단위 테스트보다 우선시됩니다.
codecov는 현재
줄 커버리지를 보고합니다.
엔드투엔드
저장소 monitor-oxc는 npm-high-impact에서 가져온 상위 3000개의 npm 패키지에 대해 엔드투엔드 테스트를 수행합니다.
그 package.json에는 3000개의 종속성이 포함되어 있습니다:
"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"
}그리고 이러한 패키지들을 불러와서 가져오기를 확인하는 테스트 파일이 있습니다:
src/dynamic.test.mjs
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 내의 모든 파일을 다시 쓴 후 실행됩니다.
패키지는 매일 최신 버전으로 업데이트됩니다.
이 설정은 일관성 테스트 세트가 놓친 많은 복잡한 버그들을 발견했습니다.
우리의 테스트 인프라를 개선할 아이디어가 있으시다면,
디스코드에서 언제든지 저희와 연락하시기 바랍니다.
