import { describe, expect, it, vi } from 'vitest'; import type { AssessorRepository } from '../../src/persistence/assessor-repository'; import type { UnifiedResultProjection } from '../../src/domain/unified-result'; import { makeSheet } from '../../src/importers/sheet-factory'; import { loadCanonicalProjectWorkspace } from '../../src/features/project-import/load-canonical-project-workspace'; import { assembleReportProjectionInput } from '../../src/features/reports/report-input-assembler'; vi.mock('../../src/features/project-import/load-canonical-project-workspace', () => ({ loadCanonicalProjectWorkspace: vi.fn() })); describe('report input assembly', () => { it('freezes only selected Dummy source facts on export without inventing environment facts or a policy verdict', async () => { const sheet = makeSheet('Dummy', [['Title', 'Source: Scan'], ['Synthetic check', 'PingCastle']], '', 'dummy.csv', { isProjectSheet: true }); vi.mocked(loadCanonicalProjectWorkspace).mockResolvedValue({ models: [], assessmentIds: ['dummy-assessment'], dataset: { fileName: 'Dummy', sheets: [sheet], scanTool: 'PingCastle' } as never }); const result = { resultProjectionId: 'dummy-result', sourceKind: 'scanner-finding', sourceResultId: 'dummy-source', projectId: 'dummy-project', assessmentId: 'dummy-assessment', scanRunId: 'dummy-run', collectionRunId: 'dummy-run', title: 'Print Spooler hardening', sourceTool: 'PingCastle', severityNormalized: 'medium', outcomeNormalized: 'fail', isDeviation: true, categories: [], frameworkReferences: [], policyActualValue: 0, policyBaselineValue: 1 } as unknown as UnifiedResultProjection; const queryUnifiedResults = vi.fn(async (query: { sourceKind?: string[] }) => ({ items: query.sourceKind?.includes('scanner-finding') ? [result] : [], total: query.sourceKind?.includes('scanner-finding') ? 1 : 0, offset: 0, limit: 500 })); const repository = { getProject: vi.fn(async () => ({ id: 'dummy-project', name: 'Dummy Customer', attributes: {}, createdAt: '', updatedAt: '' })), queryUnifiedResults, getEnvironmentSnapshot: vi.fn(async () => ({ observations: [], sections: [] })), listReviews: vi.fn(async () => []), listProjectProcessingRuns: vi.fn(async () => [{ id: 'other-timeslot-processing', artifactId: 'other-artifact', diagnosticCodes: ['other-diagnostic'], status: 'complete', processors: [], completedAt: '2026-09-01T00:00:00Z' }]), listGpoPolicyAnalyses: vi.fn(async () => []), listPolicySnapshotAggregations: vi.fn(async () => []), listPolicyEvaluations: vi.fn(async () => []) } as unknown as AssessorRepository; const input = await assembleReportProjectionInput(repository, { projectId: 'dummy-project', assessmentIds: ['dummy-assessment'], scanRunIds: ['dummy-run'], generatedAt: '2026-09-23T10:00:00Z' }); expect(input.results).toEqual([result]); expect(input.domainOf(result)).toBe('hardening'); expect(input.environment).toEqual([ { key: 'Domain', value: undefined }, { key: 'Forest', value: undefined }, { key: 'Domain Controller', value: undefined } ]); // Environment counts without source data stay unknown, never zero. expect(input.technicalEnvironment?.counts.every(count => count.value === undefined)).toBe(true); expect(input.technicalEnvironment?.operatingSystems).toEqual([]); expect(input.policyEntries).toEqual([]); expect(input.delta).toBeUndefined(); expect(input.diagnostics).toEqual([]); expect(input.provenance?.some(entry => entry.id === 'other-timeslot-processing')).toBe(false); expect(queryUnifiedResults).toHaveBeenCalledWith(expect.objectContaining({ audience: 'internal-analysis', projectId: 'dummy-project', assessmentIds: ['dummy-assessment'], scanRunIds: ['dummy-run'] })); expect(repository.getEnvironmentSnapshot).toHaveBeenCalledWith(expect.objectContaining({ projectId: 'dummy-project', scanRunIds: ['dummy-run'] })); }); });