Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
27 lines
2.0 KiB
JavaScript
27 lines
2.0 KiB
JavaScript
/**
|
|
* lib/test.mjs — 작은 테스트 러너(의존성 없음). 형제 제품(AriMail)과 같은 방식: 파일을 node 로 직접 실행하면 순서대로 돈다.
|
|
* import { test, eq, ok, rejects, tmpDir, done } from '../lib/test.mjs';
|
|
* await test('이름', async () => { ... }); 실패하면 즉시 요약을 내고 종료 코드 1.
|
|
* done(); 마지막에 요약 출력.
|
|
*/
|
|
import { mkdtempSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
|
|
let passed = 0; let failed = 0; const dirs = [];
|
|
export async function test(name, fn) {
|
|
const t0 = Date.now();
|
|
try { await fn(); passed++; console.log(` ✔ ${name} (${Date.now() - t0}ms)`); }
|
|
catch (e) { failed++; console.error(` ✘ ${name}\n ${e && e.stack ? e.stack.split('\n').slice(0, 6).join('\n ') : e}`); process.exitCode = 1; }
|
|
}
|
|
export function eq(a, b, msg = '') { const sa = JSON.stringify(a); const sb = JSON.stringify(b); if (sa !== sb) throw new Error(`${msg ? msg + ': ' : ''}기대 ${sb} 실제 ${sa}`); }
|
|
export function ok(v, msg = '') { if (!v) throw new Error(`${msg || '참이어야 합니다'} (실제 ${JSON.stringify(v)})`); }
|
|
export async function rejects(fn, codeOrRe, msg = '') {
|
|
try { await fn(); } catch (e) { if (codeOrRe == null) return e; const s = `${e.code || ''} ${e.message || ''}`; if (codeOrRe instanceof RegExp ? codeOrRe.test(s) : (e.code === codeOrRe || String(e.message).includes(codeOrRe))) return e; throw new Error(`${msg || '다른 오류'}: 기대 ${codeOrRe} 실제 ${s}`); }
|
|
throw new Error(`${msg || '예외가 나야 합니다'}`);
|
|
}
|
|
/** 테스트용 임시 디렉터리(종료 시 삭제) */
|
|
export function tmpDir(prefix = 'aw-test-') { const d = mkdtempSync(join(tmpdir(), prefix)); dirs.push(d); return d; }
|
|
export function done() { for (const d of dirs) { try { rmSync(d, { recursive: true, force: true }); } catch (_) {} } console.log(`${failed ? '✘' : '✔'} 통과 ${passed} · 실패 ${failed}`); if (failed) process.exit(1); }
|
|
export const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|