import { describe, expect, it } from 'vitest'; import * as XLSX from 'xlsx'; import type { ImportSource } from '../../src/domain/import-source'; import { importSource } from '../../src/importers/engine'; import { detectImportFormat } from '../../src/importers/format-detection'; import { genericProfile } from '../../src/profiles/generic/generic-profile'; import { browserImportRuntimeAdapters } from '../../src/platform/browser/import-runtime-adapters'; function textSource(name: string, text: string, mediaType?: string): ImportSource { const bytes = new TextEncoder().encode(text); return { metadata: { name, sizeBytes: bytes.length, lastModified: 0, mediaType }, bytes }; } const options = { profiles: [genericProfile] }; describe('format and container detection', () => { it('prefers JSON structure over conflicting extension and media type hints', async () => { const source = textSource('synthetic.csv', '{"title":"Synthetic"}', 'text/csv'); const detection = detectImportFormat(source, new TextDecoder().decode(source.bytes)); expect(detection).toMatchObject({ selected: 'JSON', structurallyValidated: true }); expect(detection?.conflicts.map(item => item.signal)).toEqual(expect.arrayContaining(['extension', 'media-type'])); const imported = await importSource(source, options, browserImportRuntimeAdapters); expect(imported.format).toBe('JSON'); expect(imported.intermediate?.formatDetection).toMatchObject({ selected: 'JSON' }); expect(imported.intermediate?.diagnostics).toContainEqual(expect.objectContaining({ code: 'format-evidence-conflict' })); }); it('uses an Excel workbook signature even when the file is mislabeled as CSV', async () => { const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, XLSX.utils.aoa_to_sheet([['Title'], ['Synthetic']]), 'Findings'); const bytes = new Uint8Array(XLSX.write(workbook, { type: 'array', bookType: 'xlsx' })); const source: ImportSource = { metadata: { name: 'synthetic.csv', sizeBytes: bytes.length, lastModified: 0, mediaType: 'text/csv' }, bytes }; const imported = await importSource(source, options, browserImportRuntimeAdapters); expect(imported.format).toBe('Excel'); expect(imported.intermediate?.formatDetection).toMatchObject({ selected: 'Excel', containerKind: 'excel-zip', structurallyValidated: true }); }); it('rejects generic ZIP, unsupported binary and fake Excel inputs with structured errors', async () => { const damagedZip = new Uint8Array([0x50, 0x4b, 0x03, 0x04, 1, 2, 3]); const damagedZipSource: ImportSource = { metadata: { name: 'spoofed.csv', sizeBytes: damagedZip.length, lastModified: 0 }, bytes: damagedZip }; await expect(importSource(damagedZipSource, options, browserImportRuntimeAdapters)).rejects.toMatchObject({ diagnostics: [expect.objectContaining({ code: 'zip-directory-missing' })] }); const emptyZip = new Uint8Array([0x50, 0x4b, 0x05, 0x06, ...new Array(18).fill(0)]); const zipSource: ImportSource = { metadata: { name: 'archive.zip', sizeBytes: emptyZip.length, lastModified: 0 }, bytes: emptyZip }; await expect(importSource(zipSource, options, browserImportRuntimeAdapters)).rejects.toMatchObject({ diagnostics: [expect.objectContaining({ code: 'unsupported-container' })] }); const binary = new Uint8Array([0, 1, 2, 3, 4]); const binarySource: ImportSource = { metadata: { name: 'synthetic.csv', sizeBytes: binary.length, lastModified: 0 }, bytes: binary }; await expect(importSource(binarySource, options, browserImportRuntimeAdapters)).rejects.toMatchObject({ diagnostics: [expect.objectContaining({ code: 'unsupported-binary-format' })] }); await expect(importSource(textSource('fake.xlsx', 'not a workbook'), options, browserImportRuntimeAdapters)).rejects.toMatchObject({ diagnostics: [expect.objectContaining({ code: 'excel-signature-mismatch' })] }); }); it('applies XML security validation to content even when the extension says text', async () => { const source = textSource('synthetic.txt', ']>&secret;', 'text/plain'); await expect(importSource(source, options, browserImportRuntimeAdapters)).rejects.toMatchObject({ diagnostics: [expect.objectContaining({ code: 'xml-doctype-rejected' })] }); const disguisedJson = textSource('nested.txt', '{"level":{"value":1}}', 'text/plain'); await expect(importSource(disguisedJson, { ...options, resourcePolicy: { maximumJsonDepth: 1 } }, browserImportRuntimeAdapters)).rejects.toMatchObject({ diagnostics: [expect.objectContaining({ code: 'json-depth-limit' })] }); }); });