test: cover getSessionStats file-path read, hasContent field, and wrapped hooks format

Round 78 — shifted from catch blocks to untested conditional branches:
- getSessionStats: exercise looksLikePath → getSessionContent path (real .tmp file)
- getAllSessions: verify hasContent true/false for non-empty vs empty files
- validate-hooks: test wrapped { hooks: { PreToolUse: [...] } } production format
This commit is contained in:
Affaan Mustafa
2026-02-13 10:21:06 -08:00
parent 27ae5ea299
commit f000d9b02d
2 changed files with 85 additions and 0 deletions

View File

@@ -2007,6 +2007,30 @@ function runTests() {
cleanupTestDir(testDir);
})) passed++; else failed++;
// ── Round 78: validate-hooks.js wrapped { hooks: { ... } } format ──
console.log('\nRound 78: validate-hooks.js (wrapped hooks format):');
if (test('validates wrapped format { hooks: { PreToolUse: [...] } }', () => {
const testDir = createTestDir();
const hooksFile = path.join(testDir, 'hooks.json');
// The production hooks.json uses this wrapped format — { hooks: { ... } }
// data.hooks is the object with event types, not data itself
fs.writeFileSync(hooksFile, JSON.stringify({
"$schema": "https://json.schemastore.org/claude-code-settings.json",
hooks: {
PreToolUse: [{ matcher: 'Write', hooks: [{ type: 'command', command: 'echo ok' }] }],
PostToolUse: [{ matcher: 'Read', hooks: [{ type: 'command', command: 'echo done' }] }]
}
}));
const result = runValidatorWithDir('validate-hooks', 'HOOKS_FILE', hooksFile);
assert.strictEqual(result.code, 0,
`Should pass wrapped hooks format, got exit ${result.code}. stderr: ${result.stderr}`);
assert.ok(result.stdout.includes('Validated 2'),
`Should validate 2 matchers, got: ${result.stdout}`);
cleanupTestDir(testDir);
})) passed++; else failed++;
// Summary
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);

View File

@@ -1207,6 +1207,67 @@ src/main.ts
}
})) passed++; else failed++;
// ── Round 78: getSessionStats reads real file when given existing .tmp path ──
console.log('\nRound 78: getSessionStats (actual file path → reads from disk):');
if (test('getSessionStats reads from disk when given path to existing .tmp file', () => {
const dir = createTempSessionDir();
try {
const sessionPath = path.join(dir, '2026-03-01-test1234-session.tmp');
const content = '# Real File Stats Test\n\n**Date:** 2026-03-01\n**Started:** 09:00\n\n### Completed\n- [x] First task\n- [x] Second task\n\n### In Progress\n- [ ] Third task\n\n### Notes for Next Session\nDon\'t forget the edge cases\n';
fs.writeFileSync(sessionPath, content);
// Pass the FILE PATH (not content) — this exercises looksLikePath branch
const stats = sessionManager.getSessionStats(sessionPath);
assert.strictEqual(stats.completedItems, 2, 'Should find 2 completed items from file');
assert.strictEqual(stats.inProgressItems, 1, 'Should find 1 in-progress item from file');
assert.strictEqual(stats.totalItems, 3, 'Should find 3 total items from file');
assert.strictEqual(stats.hasNotes, true, 'Should detect notes section from file');
assert.ok(stats.lineCount > 5, `Should have multiple lines from file, got ${stats.lineCount}`);
} finally {
cleanup(dir);
}
})) passed++; else failed++;
// ── Round 78: getAllSessions hasContent field ──
console.log('\nRound 78: getAllSessions (hasContent field):');
if (test('getAllSessions hasContent is true for non-empty and false for empty files', () => {
const isoHome = path.join(os.tmpdir(), `ecc-hascontent-${Date.now()}`);
const isoSessions = path.join(isoHome, '.claude', 'sessions');
fs.mkdirSync(isoSessions, { recursive: true });
const savedHome = process.env.HOME;
const savedProfile = process.env.USERPROFILE;
try {
// Create one non-empty session and one empty session
fs.writeFileSync(path.join(isoSessions, '2026-04-01-nonempty-session.tmp'), '# Has content');
fs.writeFileSync(path.join(isoSessions, '2026-04-02-emptyfile-session.tmp'), '');
process.env.HOME = isoHome;
process.env.USERPROFILE = isoHome;
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({ limit: 100 });
assert.strictEqual(result.total, 2, 'Should find both sessions');
const nonEmpty = result.sessions.find(s => s.shortId === 'nonempty');
const empty = result.sessions.find(s => s.shortId === 'emptyfile');
assert.ok(nonEmpty, 'Should find the non-empty session');
assert.ok(empty, 'Should find the empty session');
assert.strictEqual(nonEmpty.hasContent, true, 'Non-empty file should have hasContent: true');
assert.strictEqual(empty.hasContent, false, 'Empty file should have hasContent: false');
} finally {
process.env.HOME = savedHome;
process.env.USERPROFILE = savedProfile;
delete require.cache[require.resolve('../../scripts/lib/session-manager')];
delete require.cache[require.resolve('../../scripts/lib/utils')];
fs.rmSync(isoHome, { recursive: true, force: true });
}
})) passed++; else failed++;
// ── Round 75: deleteSession catch — unlinkSync throws on read-only dir ──
console.log('\nRound 75: deleteSession (unlink failure in read-only dir):');