import { describe, expect, it } from 'vitest'; import { computeLineStats, extractGeneratedFiles, supportsInlineDiff, supportsInlineDocumentPreview, type GeneratedFile, type GeneratedFileBaseline, } from '@/lib/generated-files'; import type { RawMessage } from '@/stores/chat'; function makeWriteFile(overrides: Partial = {}): GeneratedFile { return { filePath: '/tmp/example.ts', fileName: 'example.ts', ext: '.ts', mimeType: 'text/typescript', contentType: 'code', action: 'modified', fullContent: 'const value = 2\nconsole.log(value)\n', lastSeenIndex: 1, ...overrides, }; } describe('generated-files utilities', () => { it('computes write line stats from an existing-file baseline', () => { const stats = computeLineStats( makeWriteFile({ baseline: { status: 'ok', content: 'const value = 1\nconsole.log(value)\n' }, }), ); expect(stats).toEqual({ added: 1, removed: 1 }); }); it('treats missing baseline as a new file for line stats', () => { const stats = computeLineStats( makeWriteFile({ action: 'created', baseline: { status: 'missing' }, fullContent: 'line 1\nline 2\n', }), ); expect(stats).toEqual({ added: 2, removed: 0 }); }); it('refuses to fake precise line stats when baseline is unavailable', () => { const stats = computeLineStats( makeWriteFile({ baseline: { status: 'unavailable', reason: 'outsideSandbox' }, }), ); expect(stats).toBeNull(); }); it('routes html documents to rendered inline preview and text diff support', () => { expect(supportsInlineDocumentPreview('.html')).toBe(true); expect(supportsInlineDocumentPreview('.htm')).toBe(true); expect(supportsInlineDiff({ ext: '.html', contentType: 'document' })).toBe(true); }); it('routes pdf/spreadsheet to rich-doc preview but never to text diff', () => { expect(supportsInlineDocumentPreview('.md')).toBe(true); // PDFs and spreadsheets now render through dedicated viewers, so they // qualify for inline preview... expect(supportsInlineDocumentPreview('.pdf')).toBe(true); expect(supportsInlineDocumentPreview('.xlsx')).toBe(true); // ...but diffing binary content is still meaningless, so the diff // tab stays hidden for these formats. expect(supportsInlineDiff({ ext: '.pdf', contentType: 'document' })).toBe(false); expect(supportsInlineDiff({ ext: '.xlsx', contentType: 'document' })).toBe(false); expect(supportsInlineDiff({ ext: '.docx', contentType: 'document' })).toBe(false); const stats = computeLineStats({ filePath: '/tmp/report.pdf', fileName: 'report.pdf', ext: '.pdf', mimeType: 'application/pdf', contentType: 'document', action: 'modified', fullContent: 'pretend text payload', baseline: { status: 'ok', content: 'older pretend text payload' }, lastSeenIndex: 1, }); expect(stats).toBeNull(); }); it('extracts write files with per-run baseline state and action', () => { const messages: RawMessage[] = [ { role: 'user', content: 'update file', timestamp: 1 }, { role: 'assistant', content: [{ type: 'tool_use', id: 'write-1', name: 'Write', input: { file_path: '/tmp/example.ts', content: 'const value = 2\n', }, }], }, ]; const baselineByPath = new Map([ ['/tmp/example.ts', { status: 'ok', content: 'const value = 1\n' }], ]); const files = extractGeneratedFiles(messages, 0, 1, (filePath) => baselineByPath.get(filePath)); expect(files).toHaveLength(1); expect(files[0]).toMatchObject({ filePath: '/tmp/example.ts', action: 'modified', baseline: { status: 'ok', content: 'const value = 1\n' }, }); }); it('keeps new-file writes marked as created when the baseline says missing', () => { const messages: RawMessage[] = [ { role: 'user', content: 'create file', timestamp: 1 }, { role: 'assistant', content: [{ type: 'tool_use', id: 'write-1', name: 'Write', input: { file_path: '/tmp/new-file.ts', content: 'export const created = true\n', }, }], }, ]; const files = extractGeneratedFiles(messages, 0, 1, () => ({ status: 'missing' })); expect(files).toHaveLength(1); expect(files[0]).toMatchObject({ filePath: '/tmp/new-file.ts', action: 'created', baseline: { status: 'missing' }, }); }); it('computes edit snippet stats from joined edit hunks', () => { const stats = computeLineStats({ filePath: '/tmp/example.ts', fileName: 'example.ts', ext: '.ts', mimeType: 'text/typescript', contentType: 'code', action: 'modified', edits: [ { old: 'alpha\n', new: 'beta\n' }, { old: 'gamma\n', new: 'delta\n' }, ], lastSeenIndex: 1, }); expect(stats).toEqual({ added: 2, removed: 2 }); }); });