/** * Tests for scripts/hooks/ecc-metrics-bridge.js * * Run with: node tests/hooks/ecc-metrics-bridge.test.js */ const assert = require('assert'); const { run, hashToolCall, extractFilePaths, readSessionCost } = require('../../scripts/hooks/ecc-metrics-bridge'); // 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-metrics-bridge.js ===\n'); let passed = 0; let failed = 0; // hashToolCall tests console.log('hashToolCall:'); if ( test('returns 8-char hex string', () => { const hash = hashToolCall('Bash', { command: 'ls' }); assert.strictEqual(hash.length, 8); assert.ok(/^[0-9a-f]{8}$/.test(hash), `Expected hex, got: ${hash}`); }) ) passed++; else failed++; if ( test('different Bash commands produce different hashes', () => { const h1 = hashToolCall('Bash', { command: 'ls' }); const h2 = hashToolCall('Bash', { command: 'pwd' }); assert.notStrictEqual(h1, h2); }) ) passed++; else failed++; if ( test('different Edit file_paths produce different hashes', () => { const h1 = hashToolCall('Edit', { file_path: 'a.js' }); const h2 = hashToolCall('Edit', { file_path: 'b.js' }); assert.notStrictEqual(h1, h2); }) ) passed++; else failed++; if ( test('same inputs produce same hash (deterministic)', () => { const h1 = hashToolCall('Write', { file_path: 'x.txt' }); const h2 = hashToolCall('Write', { file_path: 'x.txt' }); assert.strictEqual(h1, h2); }) ) passed++; else failed++; // extractFilePaths tests console.log('\nextractFilePaths:'); if ( test('Edit with file_path returns [file_path]', () => { const paths = extractFilePaths('Edit', { file_path: 'a.js' }); assert.deepStrictEqual(paths, ['a.js']); }) ) passed++; else failed++; if ( test('MultiEdit with edits array returns all file_paths', () => { const paths = extractFilePaths('MultiEdit', { edits: [{ file_path: 'a.js' }, { file_path: 'b.js' }] }); assert.deepStrictEqual(paths, ['a.js', 'b.js']); }) ) passed++; else failed++; if ( test('Bash with command returns empty array', () => { const paths = extractFilePaths('Bash', { command: 'ls' }); assert.deepStrictEqual(paths, []); }) ) passed++; else failed++; if ( test('null toolInput returns empty array', () => { const paths = extractFilePaths('Edit', null); assert.deepStrictEqual(paths, []); }) ) passed++; else failed++; // readSessionCost tests console.log('\nreadSessionCost:'); if ( test('nonexistent session returns object with numeric fields', () => { const result = readSessionCost('nonexistent-session-cost-test-xyz-999'); assert.strictEqual(typeof result.totalCost, 'number'); assert.strictEqual(typeof result.totalIn, 'number'); assert.strictEqual(typeof result.totalOut, 'number'); assert.ok(result.totalCost >= 0, 'totalCost should be non-negative'); }) ) passed++; else failed++; // run tests console.log('\nrun:'); if ( test('empty input returns empty input without crashing', () => { const result = run(''); assert.strictEqual(result, ''); }) ) passed++; else failed++; if ( test('whitespace-only 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', tool_input: { command: 'ls' } }); 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);