@@ -9,10 +9,15 @@ import fs from 'node:fs';
99import os from 'node:os' ;
1010import path from 'node:path' ;
1111import Database from 'better-sqlite3' ;
12- import { afterAll , beforeAll , describe , expect , test } from 'vitest' ;
12+ import { afterAll , beforeAll , describe , expect , test , vi } from 'vitest' ;
1313import { complexityData } from '../../src/complexity.js' ;
14+ import { loadConfig } from '../../src/config.js' ;
1415import { initSchema } from '../../src/db.js' ;
1516
17+ vi . mock ( '../../src/config.js' , ( ) => ( {
18+ loadConfig : vi . fn ( ( ) => ( { } ) ) ,
19+ } ) ) ;
20+
1621// ─── Helpers ───────────────────────────────────────────────────────────
1722
1823function insertNode ( db , name , kind , file , line , endLine = null ) {
@@ -320,4 +325,42 @@ describe('complexityData', () => {
320325 expect ( typeof fn . maintainabilityIndex ) . toBe ( 'number' ) ;
321326 }
322327 } ) ;
328+
329+ // ─── Threshold sanitization (regression) ────────────────────────────
330+
331+ test ( 'non-numeric threshold values do not crash SQL query' , ( ) => {
332+ vi . mocked ( loadConfig ) . mockReturnValueOnce ( {
333+ manifesto : {
334+ rules : {
335+ cognitive : { warn : 'abc' } ,
336+ cyclomatic : { warn : '123xyz' } ,
337+ maxNesting : { warn : undefined } ,
338+ } ,
339+ } ,
340+ } ) ;
341+ // Should not throw — invalid thresholds are silently skipped
342+ const data = complexityData ( dbPath , { aboveThreshold : true } ) ;
343+ expect ( data . functions ) . toBeDefined ( ) ;
344+ expect ( Array . isArray ( data . functions ) ) . toBe ( true ) ;
345+ // With all thresholds invalid, no filtering occurs — all functions returned
346+ expect ( data . functions . length ) . toBeGreaterThanOrEqual ( 4 ) ;
347+ expect ( data . summary . aboveWarn ) . toBe ( 0 ) ;
348+ } ) ;
349+
350+ test ( 'string-numeric thresholds are rejected (strict type check)' , ( ) => {
351+ vi . mocked ( loadConfig ) . mockReturnValueOnce ( {
352+ manifesto : {
353+ rules : {
354+ cognitive : { warn : '15' } ,
355+ cyclomatic : { warn : '10' } ,
356+ maxNesting : { warn : '4' } ,
357+ } ,
358+ } ,
359+ } ) ;
360+ const data = complexityData ( dbPath , { aboveThreshold : true } ) ;
361+ // String thresholds fail typeof === 'number' — treated as no threshold
362+ // so all functions are returned (no HAVING filter applied)
363+ expect ( data . functions . length ) . toBeGreaterThanOrEqual ( 4 ) ;
364+ expect ( data . summary . aboveWarn ) . toBe ( 0 ) ;
365+ } ) ;
323366} ) ;
0 commit comments