// benchmark.test.mjs — Tests for --benchmark mode in attack-simulator.mjs // Verifies: flag parsing, report schema, block rates are valid numbers import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { resolve } from 'node:path'; import { execFile } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { formatBenchmarkJson } from '../../scanners/attack-simulator.mjs'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); const SIMULATOR = resolve(__dirname, '../../scanners/attack-simulator.mjs'); function run(args) { return new Promise((resolve, reject) => { execFile('node', [SIMULATOR, ...args], { timeout: 120_000 }, (err, stdout, stderr) => { resolve({ err, stdout, stderr, code: err?.code ?? 0 }); }); }); } describe('attack-simulator --benchmark', () => { it('--benchmark --json produces valid JSON with required fields', async () => { const { stdout } = await run(['--benchmark', '--json']); const d = JSON.parse(stdout); // Meta fields assert.ok(d.meta, 'Should have meta'); assert.ok(d.meta.timestamp, 'Should have timestamp'); assert.ok(d.meta.version, 'Should have version'); assert.ok(d.meta.node_version, 'Should have node_version'); assert.equal(typeof d.meta.scenarios_total, 'number'); // Summary fields assert.ok(d.summary, 'Should have summary'); assert.equal(typeof d.summary.block_rate, 'number'); assert.ok(d.summary.block_rate >= 0 && d.summary.block_rate <= 1, 'block_rate should be 0-1'); assert.equal(typeof d.summary.adaptive_block_rate, 'number'); assert.ok(d.summary.adaptive_block_rate >= 0 && d.summary.adaptive_block_rate <= 1); assert.equal(typeof d.summary.total_blocked, 'number'); assert.equal(typeof d.summary.total_bypassed, 'number'); // Categories assert.ok(d.categories, 'Should have categories'); assert.equal(typeof d.categories, 'object'); // Methodology assert.ok(d.methodology, 'Should have methodology string'); assert.equal(typeof d.methodology, 'string'); }); it('formatBenchmarkJson returns valid structure from mock data', () => { const mockFixed = [ { id: 'S01', name: 'test', category: 'secrets', passed: true, detail: '' }, { id: 'S02', name: 'test2', category: 'secrets', passed: false, detail: 'gap' }, ]; const mockAdaptive = [ { scenarioId: 'S01', mutation: 'homoglyph', round: 2, bypassed: true }, ]; const result = formatBenchmarkJson(mockFixed, mockAdaptive, 1000); assert.equal(result.meta.mode, 'benchmark'); assert.equal(result.summary.block_rate, 0.5); assert.equal(typeof result.summary.adaptive_block_rate, 'number'); assert.ok(result.categories.secrets); assert.equal(result.categories.secrets.scenarios, 2); assert.equal(result.categories.secrets.blocked, 1); }); });