codeburn/packages/core/tests/diagnostics.test.ts

90 lines
3.1 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
DIAGNOSTIC_DETAIL_MAX,
DiagnosticDetail,
RecordDiagnostic,
isolateRecords,
sanitizeDetail,
} from '../src/diagnostics.js'
import type { SessionObservation } from '../src/observations.js'
const fakeSession = (ref: string): SessionObservation => ({
sessionRef: ref,
projectRef: '0000000000000000',
providerId: 'claude',
startedAt: '2026-07-17T10:00:00.000Z',
calls: [],
turnCount: 0,
})
describe('DiagnosticDetail validator', () => {
it('accepts a bounded, path-free message', () => {
expect(DiagnosticDetail.safeParse('unexpected token at position 4').success).toBe(true)
})
it('rejects forward-slash paths', () => {
expect(DiagnosticDetail.safeParse('failed on /home/u/secret.json').success).toBe(false)
})
it('rejects backslash paths', () => {
expect(DiagnosticDetail.safeParse('failed on C:\\Users\\me\\x').success).toBe(false)
})
it('rejects strings over the max length', () => {
expect(DiagnosticDetail.safeParse('x'.repeat(DIAGNOSTIC_DETAIL_MAX + 1)).success).toBe(false)
})
it('RecordDiagnostic is strict (rejects unknown fields)', () => {
expect(
RecordDiagnostic.safeParse({ code: 'other', detail: 'ok', extra: 'nope' }).success,
).toBe(false)
})
})
describe('sanitizeDetail', () => {
it('strips path separators so the result passes DiagnosticDetail', () => {
const out = sanitizeDetail(new Error('cannot read /etc/passwd or C:\\secret'))
expect(out).not.toMatch(/[\\/]/)
expect(DiagnosticDetail.safeParse(out).success).toBe(true)
})
it('caps length at the max', () => {
expect(sanitizeDetail('y'.repeat(1000)).length).toBe(DIAGNOSTIC_DETAIL_MAX)
})
})
describe('isolateRecords poison isolation', () => {
it('a throwing record becomes a diagnostic and never drops its siblings', () => {
const records = ['good-1', 'POISON', 'good-2']
const { observations, diagnostics } = isolateRecords(records, (record, index) => {
if (record === 'POISON') throw new Error('kaboom at /secret/path')
return { observations: [fakeSession(`ref-${index}`)] }
})
expect(observations.map((o) => o.sessionRef)).toEqual(['ref-0', 'ref-2'])
expect(diagnostics).toHaveLength(1)
expect(diagnostics[0].index).toBe(1)
expect(diagnostics[0].code).toBe('other')
// The thrown message's path must have been sanitized out.
expect(diagnostics[0].detail).not.toMatch(/[\\/]/)
expect(RecordDiagnostic.safeParse(diagnostics[0]).success).toBe(true)
})
it('aggregates observations and diagnostics returned by decodeOne', () => {
const { observations, diagnostics } = isolateRecords([1, 2], (_r, index) => ({
observations: [fakeSession(`s-${index}`)],
diagnostics: [{ index, code: 'invalid-value' as const, detail: 'clamped a value' }],
}))
expect(observations).toHaveLength(2)
expect(diagnostics).toHaveLength(2)
})
it('never throws even when every record is poison', () => {
const { observations, diagnostics } = isolateRecords(['a', 'b'], () => {
throw new Error('always bad')
})
expect(observations).toEqual([])
expect(diagnostics).toHaveLength(2)
})
})