import { describe, expect, it } from 'vitest'; import { validateProject } from '@/domain/validation/engine'; import { hoechstgeschwindigkeitBefunde } from '@/domain/validation/rules'; import { buildSignalPlan } from '@/domain/plan/signalPlan'; import { createConflict, createPhase, createSignalGroup, createStandardIntersectionProject, } from '@/domain/model/factory'; import type { Project } from '@/domain/model/project'; /* * Befund 39, behoben in Fassung 5.9.0 - zwei Meldungen des Pruefberichts * behaupteten fest "5 s" Gelbzeit. * * Angesetzt wird in beiden Faellen die oberste Stufe der Gelbzeitstaffel, also * der Vorgabenwert "Gelbzeit Kfz über 60 km/h". Er ist von 3 bis 10 s * einstellbar. Weil die Ueberfahrzeit des Kraftfahrzeugverkehrs im Regelansatz * DIE Gelbzeit ist, geht der Wert unmittelbar in jede Zwischenzeit ein: Mit * 3 s rechnet der Plan 2 s kuerzer, als der Bericht behauptet - der Pruefer * haelt den Plan fuer sicherer, als er ist. */ const DATUM = new Date('2026-01-01T00:00:00Z'); /** Der Musterknotenpunkt mit einer abweichenden obersten Gelbzeitstufe. */ function mitGelbzeit(oberste: number, aendereK1: (g: Project['signalGroups'][number]) => object) { const roh = createStandardIntersectionProject('Gelbzeit', DATUM); return { ...roh, settings: { ...roh.settings, rilsa: { ...roh.settings.rilsa, yellowKfzAbove60: oberste } }, signalGroups: roh.signalGroups.map((g) => (g.name === 'K1' ? { ...g, ...aendereK1(g) } : g)), } satisfies Project; } describe('Befund 39 - Die genannte Gelbzeit stammt aus den wirksamen Vorgaben', () => { it('nennt bei fehlender Hoechstgeschwindigkeit die angesetzte und nicht die fest eingeschriebene Gelbzeit', () => { // Erreichbar ueber den Altdatei-Pfad: Eine 4.x-Datei mit // "geschwindigkeit: 0" an einer Kfz-Gruppe wird ungeprueft uebernommen. const project = mitGelbzeit(8, () => ({ vZul: 0 })); const befund = validateProject(project, buildSignalPlan(project), DATUM).findings.find( (f) => f.rule === 'signalgruppen.geschwindigkeit-fehlt', ); expect(befund?.message).toContain('8 s'); expect(befund?.message).not.toContain('5 s'); }); it('nennt ueber 70 km/h die angesetzte und nicht die fest eingeschriebene Gelbzeit', () => { const project = mitGelbzeit(8, () => ({ vZul: 90 })); const befund = validateProject(project, buildSignalPlan(project), DATUM).findings.find( (f) => f.rule === 'signalgruppen.vzul-ueber-70', ); expect(befund?.message).toContain('8 s'); expect(befund?.message).not.toContain('5 s'); }); it('bleibt bei den Regelvorgaben bei 5 s', () => { // Die Gegenprobe: Ohne Aenderung der Vorgaben darf sich am Wortlaut // nichts verschieben. const project = mitGelbzeit(5, () => ({ vZul: 90 })); const befund = validateProject(project, buildSignalPlan(project), DATUM).findings.find( (f) => f.rule === 'signalgruppen.vzul-ueber-70', ); expect(befund?.message).toContain('5 s'); }); it('behauptet fuer eine OePNV-Gruppe keine Gelbzeit', () => { // OePNV-Sondersignale (Balkensignale) kennen kein Gelb; yellowTime liefert // dort 0 s. Der Satz "Die Gelbzeit ist mit 5 s angesetzt" war schon mit den // Regelvorgaben falsch - und ohne jede Vorgabenaenderung erreichbar. const roh = createStandardIntersectionProject('ÖPNV', DATUM); const k1 = roh.signalGroups.find((g) => g.name === 'K1')!; const bahn = { ...createSignalGroup({ name: 'B1', mode: 'oepnv', index: 6 }), vZul: 90 }; const phase3 = createPhase('Phase 3 - ÖPNV', [bahn.id]); const project: Project = { ...roh, signalGroups: [...roh.signalGroups, bahn], phases: [...roh.phases, phase3], program: { ...roh.program, phaseOrder: [...roh.program.phaseOrder, phase3.id] }, conflicts: [ ...roh.conflicts, { ...createConflict(bahn.id, k1.id), clearingDistance: 20, enteringDistance: 8 }, ], }; const befund = hoechstgeschwindigkeitBefunde(project, buildSignalPlan(project).defaults).find( (f) => f.rule === 'signalgruppen.vzul-ueber-70' && f.target?.id === bahn.id, ); /* * NACHGEZOGEN MIT 5.27.0: Der Satz sagte "haben keine Gelbzeit" und liess * damit offen, dass ueberhaupt ein Uebergang geschaltet wird. Gesondert * signalisierte Strassenbahnen bekommen ein Uebergangssignal nach * Par. 51 BOStrab, dessen Dauer die RiLSA 2015 in Abschnitt 2.4 staffelt; * oberhalb 70 km/h gilt die oberste Stufe von 8 s. */ expect(befund).toBeDefined(); expect(befund?.message).not.toContain('Gelbzeit ist mit 5 s'); expect(befund?.message).toContain('kein Gelb, sondern ein Übergangssignal'); expect(befund?.message).toContain('8 s'); }); });