From 18fcb881688ca0ea45d86ccc67a623c9e853bb19 Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Fri, 13 Feb 2026 15:28:06 -0800 Subject: [PATCH] test: add 3 tests for whitespace ID, lastIndex reuse, and whitespace search (Round 97) --- tests/lib/session-manager.test.js | 21 +++++++++++++ tests/lib/utils.test.js | 50 +++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/tests/lib/session-manager.test.js b/tests/lib/session-manager.test.js index 1f81a1db..f7523d2a 100644 --- a/tests/lib/session-manager.test.js +++ b/tests/lib/session-manager.test.js @@ -1544,6 +1544,27 @@ src/main.ts 'Should return at most 1 session (clamped limit)'); })) passed++; else failed++; + // ── Round 97: getAllSessions with whitespace search filters out everything ── + console.log('\nRound 97: getAllSessions (whitespace search — truthy but unmatched):'); + + if (test('getAllSessions with search: " " returns empty because space is truthy but never matches shortId', () => { + // session-manager.js line 233: if (search && !metadata.shortId.includes(search)) + // ' ' (space) is truthy so the filter is applied, but shortIds are hex strings + // that never contain spaces, so ALL sessions are filtered out. + // The search filter is inside the loop, so total is also 0. + const result = sessionManager.getAllSessions({ search: ' ', limit: 100 }); + assert.strictEqual(result.sessions.length, 0, + 'Whitespace search should filter out all sessions (space never appears in hex shortIds)'); + assert.strictEqual(result.total, 0, + 'Total should be 0 because search filter is applied inside the loop (line 233)'); + assert.strictEqual(result.hasMore, false, + 'hasMore should be false since no sessions matched'); + // Contrast with null/empty search which returns all sessions: + const allResult = sessionManager.getAllSessions({ search: null, limit: 100 }); + assert.ok(allResult.total > 0, + 'Null search should return sessions (confirming they exist but space filtered them)'); + })) 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 67c2d737..c43d4c31 100644 --- a/tests/lib/utils.test.js +++ b/tests/lib/utils.test.js @@ -1300,6 +1300,56 @@ function runTests() { } })) passed++; else failed++; + // ── Round 97: getSessionIdShort with whitespace-only CLAUDE_SESSION_ID ── + console.log('\nRound 97: getSessionIdShort (whitespace-only session ID):'); + + if (test('getSessionIdShort returns whitespace when CLAUDE_SESSION_ID is all spaces', () => { + // utils.js line 116: if (sessionId && sessionId.length > 0) — ' ' is truthy + // and has length > 0, so it passes the check instead of falling back. + const original = process.env.CLAUDE_SESSION_ID; + try { + process.env.CLAUDE_SESSION_ID = ' '; // 10 spaces + const result = utils.getSessionIdShort('fallback'); + // slice(-8) on 10 spaces returns 8 spaces — not the expected fallback + assert.strictEqual(result, ' ', + 'Whitespace-only ID should return 8 trailing spaces (no trim check)'); + assert.strictEqual(result.trim().length, 0, + 'Result should be entirely whitespace (demonstrating the missing trim)'); + } finally { + if (original !== undefined) { + process.env.CLAUDE_SESSION_ID = original; + } else { + delete process.env.CLAUDE_SESSION_ID; + } + } + })) passed++; else failed++; + + // ── Round 97: countInFile with same RegExp object called twice (lastIndex reuse) ── + console.log('\nRound 97: countInFile (RegExp lastIndex reuse validation):'); + + if (test('countInFile returns consistent count when same RegExp object is reused', () => { + // utils.js lines 438-440: Always creates a new RegExp to prevent lastIndex + // state bugs. Without this defense, a global regex's lastIndex would persist + // between calls, causing alternating match/miss behavior. + const tmpDir = fs.mkdtempSync(path.join(utils.getTempDir(), 'r97-lastindex-')); + const testFile = path.join(tmpDir, 'test.txt'); + try { + fs.writeFileSync(testFile, 'foo bar foo baz foo\nfoo again foo'); + const sharedRegex = /foo/g; + // First call + const count1 = utils.countInFile(testFile, sharedRegex); + // Second call with SAME regex object — would fail without defensive new RegExp + const count2 = utils.countInFile(testFile, sharedRegex); + assert.strictEqual(count1, 5, 'First call should find 5 matches'); + assert.strictEqual(count2, 5, + 'Second call with same RegExp should also find 5 (lastIndex reset by defensive code)'); + assert.strictEqual(count1, count2, + 'Both calls must return identical counts (proves lastIndex is not shared)'); + } finally { + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + })) passed++; else failed++; + // Summary console.log('\n=== Test Results ==='); console.log(`Passed: ${passed}`);