import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { SEVERITY, WEIGHTS, riskScore, verdict, riskBand, gradeFromPassRate, QUALITY_CATEGORIES } from '../../scanners/lib/severity.mjs'; describe('SEVERITY constants', () => { it('has all 5 levels', () => { assert.deepStrictEqual(Object.keys(SEVERITY).sort(), ['critical', 'high', 'info', 'low', 'medium']); }); it('is frozen', () => { assert.throws(() => { SEVERITY.critical = 'x'; }, TypeError); }); }); describe('WEIGHTS named export (v5 F3 prep)', () => { it('exposes critical=25', () => { assert.strictEqual(WEIGHTS.critical, 25); }); it('exposes high=10, medium=4, low=1, info=0', () => { assert.strictEqual(WEIGHTS.high, 10); assert.strictEqual(WEIGHTS.medium, 4); assert.strictEqual(WEIGHTS.low, 1); assert.strictEqual(WEIGHTS.info, 0); }); }); describe('riskScore', () => { it('returns 0 for empty counts', () => { assert.strictEqual(riskScore({}), 0); }); it('returns 0 for info-only findings', () => { assert.strictEqual(riskScore({ info: 10 }), 0); }); it('scores low findings at 1 point each', () => { assert.strictEqual(riskScore({ low: 5 }), 5); }); it('scores medium findings at 4 points each', () => { assert.strictEqual(riskScore({ medium: 3 }), 12); }); it('scores high findings at 10 points each', () => { assert.strictEqual(riskScore({ high: 2 }), 20); }); it('scores critical findings at 25 points each', () => { assert.strictEqual(riskScore({ critical: 1 }), 25); }); it('caps at 100', () => { assert.strictEqual(riskScore({ critical: 10 }), 100); }); it('combines all severities', () => { assert.strictEqual(riskScore({ critical: 1, high: 1, medium: 1, low: 1, info: 1 }), 40); }); }); describe('verdict', () => { it('returns PASS for no findings', () => { assert.strictEqual(verdict({}), 'PASS'); }); it('returns PASS for low findings only', () => { assert.strictEqual(verdict({ low: 5, info: 10 }), 'PASS'); }); it('returns WARNING for any high finding', () => { assert.strictEqual(verdict({ high: 1 }), 'WARNING'); }); it('returns FAIL for any critical finding', () => { assert.strictEqual(verdict({ critical: 1 }), 'FAIL'); }); it('returns FAIL for score >= 61', () => { assert.strictEqual(verdict({ high: 6, medium: 1 }), 'FAIL'); }); it('returns WARNING for score >= 21', () => { assert.strictEqual(verdict({ medium: 6 }), 'WARNING'); }); }); describe('riskBand', () => { it('returns Low for score 0', () => { assert.strictEqual(riskBand(0), 'Low'); }); it('returns Low for score 10', () => { assert.strictEqual(riskBand(10), 'Low'); }); it('returns Medium for score 11-30', () => { assert.strictEqual(riskBand(20), 'Medium'); }); it('returns High for score 31-60', () => { assert.strictEqual(riskBand(50), 'High'); }); it('returns Critical for score 61-80', () => { assert.strictEqual(riskBand(70), 'Critical'); }); it('returns Extreme for score > 80', () => { assert.strictEqual(riskBand(90), 'Extreme'); }); }); describe('gradeFromPassRate', () => { it('returns A for 90+', () => { assert.strictEqual(gradeFromPassRate(95), 'A'); }); it('returns B for 75-89', () => { assert.strictEqual(gradeFromPassRate(80), 'B'); }); it('returns C for 60-74', () => { assert.strictEqual(gradeFromPassRate(65), 'C'); }); it('returns D for 40-59', () => { assert.strictEqual(gradeFromPassRate(50), 'D'); }); it('returns F for below 40', () => { assert.strictEqual(gradeFromPassRate(20), 'F'); }); }); describe('QUALITY_CATEGORIES', () => { it('has expected categories', () => { assert.ok(QUALITY_CATEGORIES.STRUCTURE); assert.ok(QUALITY_CATEGORIES.FEATURES); assert.ok(QUALITY_CATEGORIES.SECURITY); }); it('is frozen', () => { assert.throws(() => { QUALITY_CATEGORIES.NEW = 'x'; }, TypeError); }); });