import { describe, expect, it, vi } from 'vitest'; import { createAssessmentContext, reuseContextReads, type ContextReadPort } from '../../src/assessment-context/context-run'; import { buildAssessmentContext } from '../../src/assessment-context/context-engine'; import { contextGapReport } from '../../src/assessment-context/context-gaps'; import { RELEASED_ASSESSMENT_CONTEXT_CATALOG as catalog } from '../../src/assessment-context/context-catalog'; function source(): ContextReadPort { return { currentRevision: async () => 7, queryUnifiedResults: async () => ({ items: [], total: 0 }), listGpoPolicyAnalyses: async () => [], listReferenceRuns: async () => [], getEnvironmentSnapshot: vi.fn() as never, listPolicyEvaluations: vi.fn(async () => []), listMicrosoftSecurityBaselineAnalyses: vi.fn(async () => []), listAssessments: vi.fn(async () => []), loadAssessmentModel: vi.fn(async () => null) }; } describe('Context read reuse without persistent engine storage', () => { it('reads evaluations, templates and models once per exact argument, retaining complete independent values', async () => { const port = source(); const records = [{ id: 'synthetic', results: [{ original: 'Complete source', verdict: 'deviation' }], provenance: ['original run'] }]; const evaluations = vi.fn(async () => structuredClone(records)); port.listPolicyEvaluations = evaluations as never; const reuse = reuseContextReads(port); const [first, second] = await Promise.all([reuse.listPolicyEvaluations('p'), reuse.listPolicyEvaluations('p')]); expect(first).toEqual(records); expect(second).toEqual(records); expect(first).not.toBe(second); (first as unknown as typeof records)[0].results[0].original = 'changed by reader'; expect(await reuse.listPolicyEvaluations('p')).toEqual(records); expect(evaluations).toHaveBeenCalledTimes(1); await reuse.listPolicyEvaluations('other'); expect(evaluations).toHaveBeenCalledTimes(2); await reuse.listMicrosoftSecurityBaselineAnalyses!('baseline'); await reuse.listMicrosoftSecurityBaselineAnalyses!('baseline'); await reuse.loadAssessmentModel!('assessment'); await reuse.loadAssessmentModel!('assessment'); expect(port.listMicrosoftSecurityBaselineAnalyses).toHaveBeenCalledTimes(1); expect(port.loadAssessmentModel).toHaveBeenCalledTimes(1); await reuseContextReads(port).listPolicyEvaluations('p'); expect(evaluations).toHaveBeenCalledTimes(3); }); it('does not retain failed reads or invent optional read capabilities', async () => { const port = source(); const read = vi.fn().mockRejectedValueOnce(new Error('temporary')).mockResolvedValue([]); port.listPolicyEvaluations = read; delete port.loadAssessmentModel; const reuse = reuseContextReads(port); expect(reuse.loadAssessmentModel).toBeUndefined(); await expect(reuse.listPolicyEvaluations('p')).rejects.toThrow('temporary'); expect(await reuse.listPolicyEvaluations('p')).toEqual([]); expect(read).toHaveBeenCalledTimes(2); }); it('repeats all necessary reads on revision change and delivers the same complete Context as direct derivation', async () => { const port = source(); let revision = 7; port.currentRevision = async () => revision; port.listReferenceRuns = async () => { revision = 8; return []; }; const scope = { projectId: 'synthetic', assessmentIds: ['a'], generatedAt: '2026-10-02T00:00:00Z' }; const actual = await createAssessmentContext(port, scope); const direct = buildAssessmentContext({ ...scope, repositoryRevision: 8, observations: [], evaluations: [], analyses: [], scannerFindings: [], referenceRuns: [], cisReportSections: [], identityTargets: [], catalog }); expect(actual).toEqual({ ...direct, gapReport: contextGapReport(direct, catalog) }); expect(port.listPolicyEvaluations).toHaveBeenCalledTimes(2); expect(revision).toBe(8); }); });