Files
Dune/tools/test-discovery.ts
T
Quintine e9830b6ced Accelerate rules-first feedback and integrate native Strongholds
Apply user priority: save/recovery/privacy/custody assurance after all rules. Add quick types/lint, concise failure-preserving reporter, verbose mode, actual empty-execution guard, signal handling and focused verify name selection; compact canonical context/handoffs without mass moves. Tooling15, six negative CLI, named/empty source-bound smokes,206 doc links; same15-case278B vs2455B,2.35s vs2.36s no compute speedclaim. Native Advanced Ix/CHOAM47-card Stronghold profile: actual firstMentat/HMS/sixeffects,18native/four legalpolicies,five genuine2..6games3129actions/no rejection, human390px LAUDR2WNv14 bank2/personal1 plan and real battle. Earlier162/6513 checks before assurance amendment; finalquick25/build/guide pass. No new preservation/privacy audit or public/deployed/full-mode claim.
2026-10-02 09:30:52 +10:00

59 lines
2.2 KiB
TypeScript

import { readdirSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
export type TestKind = 'unit' | 'recovery' | 'integration';
export type TestSuite = TestKind | 'offline' | 'multiplayer' | 'all';
export type TestFile = { path: string; kind: TestKind };
// HTTP tests opt in explicitly. SQLite recovery tests use disposable memory DBs.
export function classifyTest(source: string): TestKind {
if (/^\/\/ @dune-suite integration\s*$/m.test(source)) return 'integration';
if (/^import\b[^\n]*from ['"]node:sqlite['"]/m.test(source))
return 'recovery';
return 'unit';
}
export function discoverTests(root: string, directory = 'tests'): TestFile[] {
return readdirSync(join(root, directory), { withFileTypes: true })
.sort((a, b) => a.name.localeCompare(b.name))
.flatMap((entry): TestFile[] => {
const path = `${directory}/${entry.name}`;
if (entry.isDirectory()) return discoverTests(root, path);
if (!entry.isFile() || !/\.test\.(?:ts|tsx|mts|js|mjs)$/.test(entry.name))
return [];
const source = readFileSync(join(root, path), 'utf8');
const kind = classifyTest(source);
if (
/process\.env\.DUNE_TEST_URL\b/.test(source) &&
kind !== 'integration'
)
throw new Error(`${path}: HTTP tests need // @dune-suite integration`);
return [{ path, kind }];
});
}
export function selectTests(
files: TestFile[],
suite: TestSuite,
filters: string[] = [],
): TestFile[] {
if (filters.some((filter) => !filter))
throw new Error('Filename filters must not be empty.');
const selected = files.filter(({ path, kind }) => {
const included =
suite === 'all' ||
(suite === 'offline' && kind !== 'integration') ||
(suite === 'multiplayer' && kind !== 'unit') ||
suite === kind;
return (
included && (!filters.length || filters.some((f) => path.includes(f)))
);
});
// A typo should never produce a green run that executed no tests.
for (const filter of filters)
if (!selected.some(({ path }) => path.includes(filter)))
throw new Error(`No ${suite} test files match "${filter}".`);
if (!selected.length) throw new Error(`No test files in suite "${suite}".`);
return selected;
}