import 'reflect-metadata'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import test from 'node:test'; import { REQUIRED_PERMISSIONS_KEY } from '../../src/authorization/decorators/require-permissions.decorator'; import { InspectionFindingRecurrenceController } from '../../src/inspection-findings/inspection-finding-recurrence.controller'; const root = process.cwd(); const read = (relative: string) => fs.readFileSync(path.join(root, relative), 'utf8'); function permissions(method: string): string[] { const handler = InspectionFindingRecurrenceController.prototype[ method as keyof InspectionFindingRecurrenceController ]; return Reflect.getMetadata(REQUIRED_PERMISSIONS_KEY, handler) as string[]; } test('F4 exposes recurrence candidates for the selected Inventory and creates a new Finding', () => { assert.deepEqual(permissions('candidates'), ['inspection_findings.read']); assert.deepEqual(permissions('create'), ['inspection_findings.create']); }); test('F4 recurrence only accepts an unresolved prior Finding from the same Inventory context', () => { const service = read('src/inspection-findings/inspection-finding-recurrence.service.ts'); assert.match(service, /finding\.status = 'OPEN'/); assert.match(service, /INSPECTION_FINDING_ANTECEDENT_RESOLVED/); assert.match(service, /INSPECTION_FINDING_RECURRENCE_ASSET_NOT_IN_ACT/); assert.match(service, /finding\.act_id <> \$2/); }); test('F4 creates recurrence append-only as a new Finding linked to its antecedent', () => { const service = read('src/inspection-findings/inspection-finding-recurrence.service.ts'); assert.match(service, /is_recurrence/); assert.match(service, /antecedent_finding_id/); assert.match(service, /INSERT INTO inspection_finding_versions/); assert.match(service, /recurrence: true/); assert.doesNotMatch(service, /UPDATE inspection_findings[\s\S]*antecedentFindingId/); });