/** * Tests for scripts/hooks/ecc-context-monitor.js * * Run with: node tests/hooks/ecc-context-monitor.test.js */ const assert = require('assert'); const { run, evaluateConditions, detectLoop, severityLabel } = require('../../scripts/hooks/ecc-context-monitor'); // Test helper function test(name, fn) { try { fn(); console.log(` \u2713 ${name}`); return true; } catch (err) { console.log(` \u2717 ${name}`); console.log(` Error: ${err.message}`); return false; } } function runTests() { console.log('\n=== Testing ecc-context-monitor.js ===\n'); let passed = 0; let failed = 0; // evaluateConditions — context warnings console.log('evaluateConditions (context):'); if ( test('remaining 20% triggers CRITICAL context warning', () => { const warnings = evaluateConditions({ context_remaining_pct: 20 }); const ctx = warnings.find(w => w.type === 'context'); assert.ok(ctx, 'Expected a context warning'); assert.strictEqual(ctx.severity, 3); assert.ok(ctx.message.includes('CRITICAL'), 'Message should contain CRITICAL'); }) ) passed++; else failed++; if ( test('remaining 30% triggers WARNING context warning', () => { const warnings = evaluateConditions({ context_remaining_pct: 30 }); const ctx = warnings.find(w => w.type === 'context'); assert.ok(ctx, 'Expected a context warning'); assert.strictEqual(ctx.severity, 2); assert.ok(ctx.message.includes('WARNING'), 'Message should contain WARNING'); }) ) passed++; else failed++; if ( test('remaining 50% triggers no context warning', () => { const warnings = evaluateConditions({ context_remaining_pct: 50 }); const ctx = warnings.find(w => w.type === 'context'); assert.strictEqual(ctx, undefined); }) ) passed++; else failed++; // evaluateConditions — cost warnings console.log('\nevaluateConditions (cost):'); if ( test('cost $55 triggers CRITICAL cost warning', () => { const warnings = evaluateConditions({ total_cost_usd: 55 }); const cost = warnings.find(w => w.type === 'cost'); assert.ok(cost, 'Expected a cost warning'); assert.strictEqual(cost.severity, 3); assert.ok(cost.message.includes('CRITICAL'), 'Message should contain CRITICAL'); }) ) passed++; else failed++; if ( test('cost $12 triggers WARNING cost warning', () => { const warnings = evaluateConditions({ total_cost_usd: 12 }); const cost = warnings.find(w => w.type === 'cost'); assert.ok(cost, 'Expected a cost warning'); assert.strictEqual(cost.severity, 2); assert.ok(cost.message.includes('WARNING'), 'Message should contain WARNING'); }) ) passed++; else failed++; if ( test('cost $6 triggers NOTICE cost warning', () => { const warnings = evaluateConditions({ total_cost_usd: 6 }); const cost = warnings.find(w => w.type === 'cost'); assert.ok(cost, 'Expected a cost warning'); assert.strictEqual(cost.severity, 1); assert.ok(cost.message.includes('NOTICE'), 'Message should contain NOTICE'); }) ) passed++; else failed++; if ( test('cost $2 triggers no cost warning', () => { const warnings = evaluateConditions({ total_cost_usd: 2 }); const cost = warnings.find(w => w.type === 'cost'); assert.strictEqual(cost, undefined); }) ) passed++; else failed++; // evaluateConditions — scope warnings console.log('\nevaluateConditions (scope):'); if ( test('25 files triggers scope WARNING', () => { const warnings = evaluateConditions({ files_modified_count: 25 }); const scope = warnings.find(w => w.type === 'scope'); assert.ok(scope, 'Expected a scope warning'); assert.strictEqual(scope.severity, 2); assert.ok(scope.message.includes('SCOPE'), 'Message should contain SCOPE'); }) ) passed++; else failed++; if ( test('10 files triggers no scope warning', () => { const warnings = evaluateConditions({ files_modified_count: 10 }); const scope = warnings.find(w => w.type === 'scope'); assert.strictEqual(scope, undefined); }) ) passed++; else failed++; // detectLoop tests console.log('\ndetectLoop:'); if ( test('3 identical entries returns detected true', () => { const entries = [ { tool: 'Bash', hash: 'aabbccdd' }, { tool: 'Bash', hash: 'aabbccdd' }, { tool: 'Bash', hash: 'aabbccdd' } ]; const result = detectLoop(entries); assert.strictEqual(result.detected, true); assert.strictEqual(result.tool, 'Bash'); assert.ok(result.count >= 3); }) ) passed++; else failed++; if ( test('all different entries returns detected false', () => { const entries = [ { tool: 'Bash', hash: '11111111' }, { tool: 'Edit', hash: '22222222' }, { tool: 'Write', hash: '33333333' } ]; const result = detectLoop(entries); assert.strictEqual(result.detected, false); }) ) passed++; else failed++; if ( test('empty array returns detected false', () => { const result = detectLoop([]); assert.strictEqual(result.detected, false); }) ) passed++; else failed++; // severityLabel tests console.log('\nseverityLabel:'); if ( test('severity 3 returns critical', () => { assert.strictEqual(severityLabel(3), 'critical'); }) ) passed++; else failed++; if ( test('severity 2 returns warning', () => { assert.strictEqual(severityLabel(2), 'warning'); }) ) passed++; else failed++; if ( test('severity 1 returns notice', () => { assert.strictEqual(severityLabel(1), 'notice'); }) ) passed++; else failed++; // run tests console.log('\nrun:'); if ( test('empty input returns input unchanged', () => { const result = run(''); assert.strictEqual(result, ''); }) ) passed++; else failed++; if ( test('input without session_id returns input unchanged', () => { const input = JSON.stringify({ tool_name: 'Bash' }); const result = run(input); assert.strictEqual(result, input); }) ) passed++; else failed++; // Summary console.log(`\nResults: ${passed} passed, ${failed} failed\n`); return { passed, failed }; } const { failed } = runTests(); process.exit(failed > 0 ? 1 : 0);