From 3ec0aa7b50cb3218628d03e0ae69ca4c0fc5b8d9 Mon Sep 17 00:00:00 2001 From: Affaan Mustafa Date: Fri, 13 Feb 2026 06:44:52 -0800 Subject: [PATCH] test: add replaceInFile write failure, empty sessions dir, and corrupted global config tests (Round 61) - utils.test.js: replaceInFile returns false on read-only file (catch block) - session-manager.test.js: getAllSessions returns empty when sessions dir missing - package-manager.test.js: getPackageManager falls through corrupted global config to npm default 788 tests total, all passing. --- tests/lib/package-manager.test.js | 34 +++++++++++++++++++++++++++++++ tests/lib/session-manager.test.js | 26 +++++++++++++++++++++++ tests/lib/utils.test.js | 23 +++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/tests/lib/package-manager.test.js b/tests/lib/package-manager.test.js index 021e7dc1..a4f1eb14 100644 --- a/tests/lib/package-manager.test.js +++ b/tests/lib/package-manager.test.js @@ -1196,6 +1196,40 @@ function runTests() { } })) passed++; else failed++; + // getPackageManager falls through corrupted global config to npm default + if (test('getPackageManager falls through corrupted global config to npm default', () => { + const tmpDir = createTestDir(); + const projDir = path.join(tmpDir, 'proj'); + fs.mkdirSync(projDir, { recursive: true }); + const origHome = process.env.HOME; + const origUserProfile = process.env.USERPROFILE; + const origPM = process.env.CLAUDE_PACKAGE_MANAGER; + try { + // Create corrupted global config file + const claudeDir = path.join(tmpDir, '.claude'); + fs.mkdirSync(claudeDir, { recursive: true }); + fs.writeFileSync(path.join(claudeDir, 'package-manager.json'), '{ invalid json !!!', 'utf8'); + process.env.HOME = tmpDir; + process.env.USERPROFILE = tmpDir; + delete process.env.CLAUDE_PACKAGE_MANAGER; + // Re-require to pick up new HOME + delete require.cache[require.resolve('../../scripts/lib/package-manager')]; + delete require.cache[require.resolve('../../scripts/lib/utils')]; + const freshPM = require('../../scripts/lib/package-manager'); + // Empty project dir: no lock file, no package.json, no project config + const result = freshPM.getPackageManager({ projectDir: projDir }); + assert.strictEqual(result.name, 'npm', 'Should fall through to npm default'); + assert.strictEqual(result.source, 'default', 'Source should be default'); + } finally { + process.env.HOME = origHome; + process.env.USERPROFILE = origUserProfile; + if (origPM !== undefined) process.env.CLAUDE_PACKAGE_MANAGER = origPM; + delete require.cache[require.resolve('../../scripts/lib/package-manager')]; + delete require.cache[require.resolve('../../scripts/lib/utils')]; + cleanupTestDir(tmpDir); + } + })) passed++; else failed++; + // Summary console.log('\n=== Test Results ==='); console.log(`Passed: ${passed}`); diff --git a/tests/lib/session-manager.test.js b/tests/lib/session-manager.test.js index 9439208d..81b8e26d 100644 --- a/tests/lib/session-manager.test.js +++ b/tests/lib/session-manager.test.js @@ -1139,6 +1139,32 @@ src/main.ts assert.strictEqual(meta.completed[0], 'Lowercase task'); })) passed++; else failed++; + // getAllSessions returns empty result when sessions directory does not exist + if (test('getAllSessions returns empty when sessions dir missing', () => { + const tmpDir = createTempSessionDir(); + const origHome = process.env.HOME; + const origUserProfile = process.env.USERPROFILE; + try { + // Point HOME to a dir with no .claude/sessions/ + process.env.HOME = tmpDir; + process.env.USERPROFILE = tmpDir; + // Re-require to pick up new HOME + delete require.cache[require.resolve('../../scripts/lib/session-manager')]; + delete require.cache[require.resolve('../../scripts/lib/utils')]; + const freshSM = require('../../scripts/lib/session-manager'); + const result = freshSM.getAllSessions(); + assert.deepStrictEqual(result.sessions, [], 'Should return empty sessions array'); + assert.strictEqual(result.total, 0, 'Total should be 0'); + assert.strictEqual(result.hasMore, false, 'hasMore should be false'); + } finally { + process.env.HOME = origHome; + process.env.USERPROFILE = origUserProfile; + delete require.cache[require.resolve('../../scripts/lib/session-manager')]; + delete require.cache[require.resolve('../../scripts/lib/utils')]; + cleanup(tmpDir); + } + })) 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 955a750b..eb0c85e3 100644 --- a/tests/lib/utils.test.js +++ b/tests/lib/utils.test.js @@ -1025,6 +1025,29 @@ function runTests() { assert.strictEqual(parsed.test, 'settled-guard', 'Should parse normally when end fires first'); })) passed++; else failed++; + // replaceInFile returns false when write fails (e.g., read-only file) + if (test('replaceInFile returns false on write failure (read-only file)', () => { + if (process.platform === 'win32' || process.getuid?.() === 0) { + console.log(' (skipped — chmod ineffective on Windows/root)'); + return; + } + const testDir = path.join(utils.getTempDir(), `utils-test-readonly-${Date.now()}`); + fs.mkdirSync(testDir, { recursive: true }); + const filePath = path.join(testDir, 'readonly.txt'); + try { + fs.writeFileSync(filePath, 'hello world', 'utf8'); + fs.chmodSync(filePath, 0o444); + const result = utils.replaceInFile(filePath, 'hello', 'goodbye'); + assert.strictEqual(result, false, 'Should return false when file is read-only'); + // Verify content unchanged + const content = fs.readFileSync(filePath, 'utf8'); + assert.strictEqual(content, 'hello world', 'Original content should be preserved'); + } finally { + fs.chmodSync(filePath, 0o644); + fs.rmSync(testDir, { recursive: true, force: true }); + } + })) passed++; else failed++; + // Summary console.log('\n=== Test Results ==='); console.log(`Passed: ${passed}`);