import { describe, expect, it } from 'vitest'; import { parseProject } from '@/domain/model/schema'; /* * Befund 10, behoben in Fassung 5.9.0. * * `optionalNum` gibt bei jedem unlesbaren Eintrag `null` zurueck und meldet * nichts. Betroffen sind genau die Felder, an denen eine Zwischenzeit oder eine * Freigabezeit haengt. Eine von Hand abgestimmte Zwischenzeit "9 s" faellt damit * still auf den gerechneten - hier kuerzeren - Wert zurueck, und beim naechsten * Speichern ist sie endgueltig weg. * * Die Regel der unmittelbaren Nachbarn `boolGemeldet` und `anteilGemeldet` gilt * auch hier: Ein FEHLENDER Eintrag schweigt, ein dastehender und unlesbarer * wird gemeldet. */ describe('Unlesbare Handvorgaben beim Einlesen', () => { const zweiGruppen = [ { id: 'a', name: 'K1', mode: 'kfz' }, { id: 'b', name: 'K2', mode: 'kfz' }, ]; function mitKonfliktfeld(feld: string, wert: unknown): ReturnType { return parseProject({ signalGroups: zweiGruppen, conflicts: [ { fromId: 'a', toId: 'b', clearingDistance: 12, enteringDistance: 10, [feld]: wert, }, ], }); } it('meldet eine unlesbare abgestimmte Zwischenzeit, statt sie stumm zu verwerfen', () => { const { project, issues } = mitKonfliktfeld('manualIntergreen', '9 s'); expect(project.conflicts[0]!.manualIntergreen).toBeNull(); expect( issues.some((i) => i.path === 'conflicts[0].manualIntergreen' && i.severity === 'warnung'), ).toBe(true); }); it('meldet eine unlesbare Raeumgeschwindigkeit, statt auf die schnellere Regelgeschwindigkeit zurueckzufallen', () => { const { project, issues } = mitKonfliktfeld('clearingSpeedOverride', '1,0 m/s'); expect(project.conflicts[0]!.clearingSpeedOverride).toBeNull(); expect( issues.some( (i) => i.path === 'conflicts[0].clearingSpeedOverride' && i.severity === 'warnung', ), ).toBe(true); }); it('meldet eine unlesbare Einfahrgeschwindigkeit', () => { const { project, issues } = mitKonfliktfeld('enteringSpeedOverride', 'schnell'); expect(project.conflicts[0]!.enteringSpeedOverride).toBeNull(); expect( issues.some( (i) => i.path === 'conflicts[0].enteringSpeedOverride' && i.severity === 'warnung', ), ).toBe(true); }); it('meldet eine unlesbare Ueberfahrzeit', () => { const { project, issues } = mitKonfliktfeld('crossingTimeOverride', '3 s'); expect(project.conflicts[0]!.crossingTimeOverride).toBeNull(); expect( issues.some( (i) => i.path === 'conflicts[0].crossingTimeOverride' && i.severity === 'warnung', ), ).toBe(true); }); it('meldet eine unlesbare Mindest- und Hoechstfreigabezeit der Signalgruppe', () => { const { project, issues } = parseProject({ signalGroups: [ { id: 'a', name: 'K1', mode: 'kfz', minGreenOverride: '12 s', maxGreenOverride: 'lang' }, ], }); expect(project.signalGroups[0]!.minGreenOverride).toBeNull(); expect(project.signalGroups[0]!.maxGreenOverride).toBeNull(); expect( issues.some((i) => i.path === 'signalGroups[0].minGreenOverride' && i.severity === 'warnung'), ).toBe(true); expect( issues.some((i) => i.path === 'signalGroups[0].maxGreenOverride' && i.severity === 'warnung'), ).toBe(true); }); it('meldet eine unlesbare vorgegebene Umlaufzeit des Programms', () => { const { project, issues } = parseProject({ signalGroups: zweiGruppen, program: { method: 'manuell', manualCycleTime: '80 s' }, }); expect(project.program.manualCycleTime).toBeNull(); expect( issues.some((i) => i.path === 'program.manualCycleTime' && i.severity === 'warnung'), ).toBe(true); }); it('meldet eine unlesbare vorgegebene Freigabezeit einer Phase', () => { // Eine Handvorgabe gilt im Signalzeitenplan als FESTE Freigabezeit // (minGreen = maxGreen). Faellt sie stumm weg, verteilt der Plan nach dem // Verhaeltnis der Saettigungsgrade - die Phase kann dabei kuerzer werden. const { project, issues } = parseProject({ signalGroups: zweiGruppen, phases: [{ id: 'p1', name: 'Phase 1', signalGroupIds: ['a'], manualGreen: '25 s' }], }); expect(project.phases[0]!.manualGreen).toBeNull(); expect(issues.some((i) => i.path === 'phases[0].manualGreen' && i.severity === 'warnung')).toBe( true, ); }); it('behaelt eine lesbare Umlauf- und Freigabezeit und schweigt bei fehlenden Eintraegen', () => { const mitZahlen = parseProject({ signalGroups: zweiGruppen, program: { method: 'manuell', manualCycleTime: 80 }, phases: [{ id: 'p1', name: 'Phase 1', signalGroupIds: ['a'], manualGreen: 25 }], }); expect(mitZahlen.project.program.manualCycleTime).toBe(80); expect(mitZahlen.project.phases[0]!.manualGreen).toBe(25); expect( mitZahlen.issues.filter( (i) => i.path === 'program.manualCycleTime' || i.path === 'phases[0].manualGreen', ), ).toEqual([]); const ohneFelder = parseProject({ signalGroups: zweiGruppen, program: { method: 'webster' }, phases: [{ id: 'p1', name: 'Phase 1', signalGroupIds: ['a'] }], }); expect(ohneFelder.project.program.manualCycleTime).toBeNull(); expect(ohneFelder.project.phases[0]!.manualGreen).toBeNull(); expect(ohneFelder.repaired).toBe(false); }); it('behaelt eine lesbare Handvorgabe und schweigt bei einem fehlenden Eintrag', () => { const mitZahl = mitKonfliktfeld('manualIntergreen', 9); expect(mitZahl.project.conflicts[0]!.manualIntergreen).toBe(9); expect(mitZahl.issues.filter((i) => i.path.includes('manualIntergreen'))).toEqual([]); const ohneFeld = parseProject({ signalGroups: zweiGruppen, conflicts: [{ fromId: 'a', toId: 'b', clearingDistance: 12, enteringDistance: 10 }], }); expect(ohneFeld.project.conflicts[0]!.manualIntergreen).toBeNull(); expect(ohneFeld.issues.filter((i) => i.path.startsWith('conflicts'))).toEqual([]); expect(ohneFeld.repaired).toBe(false); }); it('nimmt das deutsche Dezimalkomma weiterhin an', () => { const { project, issues } = mitKonfliktfeld('clearingSpeedOverride', '1,5'); expect(project.conflicts[0]!.clearingSpeedOverride).toBeCloseTo(1.5, 6); expect(issues.filter((i) => i.path.includes('clearingSpeedOverride'))).toEqual([]); }); });