From 274cca025e520faadb4d4b34559c4eccffd3ac5a Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Fri, 13 Feb 2026 15:35:18 -0800 Subject: [PATCH] test: add 3 tests for null-input crashes and negative maxAge boundary (R98) - getSessionById(null) throws TypeError at line 297 (null.length) - parseSessionFilename(null) throws TypeError at line 30 (null.match()) - findFiles with maxAge: -1 deterministically excludes all files --- tests/lib/session-manager.test.js | 28 ++++++++++++++++++++++++++++ tests/lib/utils.test.js | 23 +++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/tests/lib/session-manager.test.js b/tests/lib/session-manager.test.js index f7523d2a..6fa47d48 100644 --- a/tests/lib/session-manager.test.js +++ b/tests/lib/session-manager.test.js @@ -1565,6 +1565,34 @@ src/main.ts 'Null search should return sessions (confirming they exist but space filtered them)'); })) passed++; else failed++; + // ── Round 98: getSessionById with null sessionId throws TypeError ── + console.log('\nRound 98: getSessionById (null sessionId — crashes at line 297):'); + + if (test('getSessionById(null) throws TypeError when session files exist', () => { + // session-manager.js line 297: `sessionId.length > 0` — calling .length on null + // throws TypeError because there's no early guard for null/undefined input. + // This only surfaces when valid .tmp files exist in the sessions directory. + assert.throws( + () => sessionManager.getSessionById(null), + { name: 'TypeError' }, + 'null.length should throw TypeError (no input guard at function entry)' + ); + })) passed++; else failed++; + + // ── Round 98: parseSessionFilename with null input throws TypeError ── + console.log('\nRound 98: parseSessionFilename (null input — crashes at line 30):'); + + if (test('parseSessionFilename(null) throws TypeError because null has no .match()', () => { + // session-manager.js line 30: `filename.match(SESSION_FILENAME_REGEX)` + // When filename is null, null.match() throws TypeError. + // Function lacks a type guard like `if (!filename || typeof filename !== 'string')`. + assert.throws( + () => sessionManager.parseSessionFilename(null), + { name: 'TypeError' }, + 'null.match() should throw TypeError (no type guard on filename parameter)' + ); + })) passed++; else failed++; + // Summary console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`); process.exit(failed > 0 ? 1 : 0); diff --git a/tests/lib/utils.test.js b/tests/lib/utils.test.js index c43d4c31..4281dd83 100644 --- a/tests/lib/utils.test.js +++ b/tests/lib/utils.test.js @@ -1350,6 +1350,29 @@ function runTests() { } })) passed++; else failed++; + // ── Round 98: findFiles with maxAge: -1 (negative boundary — excludes everything) ── + console.log('\nRound 98: findFiles (maxAge: -1 — negative boundary excludes all):'); + + if (test('findFiles with maxAge: -1 excludes all files (ageInDays always >= 0)', () => { + // utils.js line 176-178: `if (maxAge !== null) { ageInDays = ...; if (ageInDays <= maxAge) }` + // With maxAge: -1, the condition requires ageInDays <= -1. Since ageInDays = + // (Date.now() - mtimeMs) / 86400000 is always >= 0 for real files, nothing passes. + // This negative boundary deterministically excludes everything. + const tmpDir = fs.mkdtempSync(path.join(utils.getTempDir(), 'r98-maxage-neg-')); + try { + fs.writeFileSync(path.join(tmpDir, 'fresh.txt'), 'created just now'); + const results = utils.findFiles(tmpDir, '*.txt', { maxAge: -1 }); + assert.strictEqual(results.length, 0, + 'maxAge: -1 should exclude all files (ageInDays is always >= 0)'); + // Contrast: maxAge: null (default) should include the file + const noMaxAge = utils.findFiles(tmpDir, '*.txt'); + assert.strictEqual(noMaxAge.length, 1, + 'No maxAge (null default) should include the file (proving it exists)'); + } finally { + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + })) passed++; else failed++; + // Summary console.log('\n=== Test Results ==='); console.log(`Passed: ${passed}`);