Skip to content

Инфраструктура тестирования

INFO

Эта заметка — приглашение обмениваться идеями по улучшению тестовой инфраструктуры; можно связаться с нами в Discord.

В Oxc надёжность и корректность воспринимаются очень серьёзно.

Много времени уходит на укрепление тестовой инфраструктуры, чтобы проблемы не доходили до downstream-инструментов.

Парсер

Соответствие спецификации

Используются парсерные тесты из Test262, Babel и TypeScript для проверки синтаксиса JavaScript, TypeScript и JSX.

Для Test262 включены все тесты stage 4 и тесты регулярных выражений.

Результаты соответствия хранятся в снимках для отслеживания изменений:

Все синтаксические ошибки попадают в эти файлы-снимки для удобного диффа.

Фаззинг

Чтобы парсер не падал на случайных данных, используются три фаззера:

  1. cargo fuzz: случайные байты в парсер.
  2. shift-fuzzer-js от bakkot — случайные, но синтаксически валидные AST.
  3. Automated-Fuzzer от qarmin; он активно сообщает о падениях.

Безопасность памяти

У Oxc для AST и связанных структур используется arena на базе bumpalo. У типов узлов AST нет реализации Drop. allocator Oxc на этапе компиляции запрещает класть в arena типы с Drop, если кто-то попытается — будет ошибка компиляции. Так статически гарантируется, что владеющие кучей данные не окажутся в arena без возможности их корректно освободить.

Небезопасный код

unsafe используется ради производительности. Мы стараемся держать его внутри изолированных структур с безопасным внешним API. 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 по крупным репозиториям в поисках ложных срабатываний, регрессий и паник. Среди проверяемых:

Идемпотентность

Идемпотентное тестирование применяется в интеграционных и сквозных тестах всех инструментов.

Схема:

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

Например, повторное минифицирование одного и того же кода должно давать тот же результат.

Все инструменты (парсер, трансформер, минификатор и т.д.) идемпотентно тестируются на файлах из Test262, Babel и TypeScript.

Интеграционные тесты

Предпочтительны интеграционные тесты, а не изолированные юнит-тесты.

codecov сейчас показывает Code Coverage покрытие по строкам.

Сквозные тесты

Репозиторий monitor-oxc выполняет E2E-тесты на топ-3000 пакетов npm из npm-high-impact.

В 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"
}

И тестовый файл, который импортирует пакеты и проверяет импорт:

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));

Файл запускается после того, как инструменты (codegen, трансформер, минификатор и т.д.) переписали все файлы в node_modules.

Пакеты ежедневно обновляются до последних версий.

Так находились многие редкие баги, которые пропускали наборы соответствия.


Если есть идеи, как улучшить нашу тестовую инфраструктуру, пишите в Discord.