lsa-planer
LSA-Planer Professional – Planungssoftware für Lichtsignalanlagen nach RiLSA 2015 und § 45 StVO. EUPL-1.2.
/ tests domain freigabezeitrest.test.ts
| 1 | import { describe, expect, it } from 'vitest'; |
| 2 | import { distributeGreenTimes } from '@/domain/rilsa/greenSplit'; |
| 3 | import { validateProject } from '@/domain/validation/engine'; |
| 4 | import { buildSignalPlan, type PlanNote, type SignalPlan } from '@/domain/plan/signalPlan'; |
| 5 | import { createStandardIntersectionProject } from '@/domain/model/factory'; |
| 6 | |
| 7 | /* |
| 8 | * Zwei Restmaengel der Freigabezeitverteilung (Fassung 5.9.0). |
| 9 | * |
| 10 | * Die erste Behebung hat in die Freigabezeitverteilung einen Zweig eingezogen, der die |
| 11 | * nicht nach Verkehrsstaerken vergebene Zeit an die Phasen mit Spielraum |
| 12 | * umlegt. Er benutzte dafuer die vorhandene Kennung `freigabezeit-rest` - und |
| 13 | * erbte damit im Pruefbericht deren Ueberschrift "Freigabezeit konnte nicht |
| 14 | * vollständig verteilt werden" und deren Rat "Prüfen Sie die vorgegebenen |
| 15 | * Freigabezeiten und die Umlaufzeit". |
| 16 | * |
| 17 | * Beides ist in diesem Zweig falsch: Die Zeit IST vollstaendig vergeben, und im |
| 18 | * Regelfall - eine Fussgaengerphase ohne Verkehrsstaerke - ist nichts zu |
| 19 | * pruefen. Der Zweig bekommt deshalb eine eigene Kennung. |
| 20 | */ |
| 21 | |
| 22 | const DATUM = new Date('2026-01-01T00:00:00Z'); |
| 23 | const UMGELEGT = 'freigabezeit-rest-umgelegt'; |
| 24 | const REST = 'freigabezeit-rest'; |
| 25 | |
| 26 | /** |
| 27 | * Knotenpunkt mit fester Freigabezeit in Phase 1 und einer Fussgaengerphase |
| 28 | * ohne Verkehrsstaerke in Phase 2 - der Regelfall des neuen Zweigs. |
| 29 | * Feste Umlaufzeit 95 s, zwei Phasenuebergaenge zu je 10 s: 75 s verfuegbar. |
| 30 | */ |
| 31 | function mitUmlegung(): ReturnType<typeof distributeGreenTimes> { |
| 32 | return distributeGreenTimes( |
| 33 | 95, |
| 34 | [ |
| 35 | { id: 'p1', weight: 0.35, minGreen: 40, maxGreen: 40 }, |
| 36 | { id: 'p2', weight: 0, minGreen: 20, maxGreen: 120 }, |
| 37 | ], |
| 38 | [10, 10], |
| 39 | ); |
| 40 | } |
| 41 | |
| 42 | describe('Die Umlegung traegt eine eigene Kennung', () => { |
| 43 | it('meldet die Umlegung unter eigener Kennung', () => { |
| 44 | const ergebnis = mitUmlegung(); |
| 45 | |
| 46 | const notiz = ergebnis.notes.find((n) => n.code === UMGELEGT); |
| 47 | expect(notiz).toBeDefined(); |
| 48 | expect(notiz?.severity).toBe('hinweis'); |
| 49 | expect(notiz?.message).toContain('Phase 2'); |
| 50 | }); |
| 51 | |
| 52 | it('benutzt dafuer nicht mehr die Kennung des nicht verteilbaren Rests', () => { |
| 53 | // Bis hierher stand ueber diesem Hinweis "Freigabezeit konnte nicht |
| 54 | // vollständig verteilt werden" - waehrend die Zeit vollstaendig vergeben |
| 55 | // ist. |
| 56 | const ergebnis = mitUmlegung(); |
| 57 | |
| 58 | expect(ergebnis.notes.some((n) => n.code === REST)).toBe(false); |
| 59 | }); |
| 60 | |
| 61 | it('laesst dem wirklich nicht verteilbaren Rest seine Kennung', () => { |
| 62 | // Einstreifige Verkehrsfuehrung, feste Umlaufzeit 300 s, zwei Uebergaenge |
| 63 | // zu je 10 s; Hoechstfreigabezeit 120 s je Phase. Hier liegt am Ende jede |
| 64 | // Phase an ihrer Obergrenze - die Warnung ist am Platz. |
| 65 | const ergebnis = distributeGreenTimes( |
| 66 | 300, |
| 67 | [ |
| 68 | { id: 'p1', weight: 0.35, minGreen: 5, maxGreen: 120 }, |
| 69 | { id: 'p2', weight: 0, minGreen: 20, maxGreen: 120 }, |
| 70 | ], |
| 71 | [10, 10], |
| 72 | ); |
| 73 | |
| 74 | const warnung = ergebnis.notes.find((n) => n.code === REST); |
| 75 | expect(warnung?.severity).toBe('warnung'); |
| 76 | expect(ergebnis.notes.some((n) => n.code === UMGELEGT)).toBe(false); |
| 77 | }); |
| 78 | }); |
| 79 | |
| 80 | describe('Ueberschrift, naechster Schritt und Sachgebiet der Umlegung', () => { |
| 81 | const project = createStandardIntersectionProject('Umlegung', DATUM); |
| 82 | const plan = buildSignalPlan(project); |
| 83 | |
| 84 | function befundZu(note: PlanNote) { |
| 85 | const mitNotiz: SignalPlan = { ...plan, notes: [note] }; |
| 86 | return validateProject(project, mitNotiz, DATUM).findings.find( |
| 87 | (f) => f.rule === `signalplan.${note.code}`, |
| 88 | ); |
| 89 | } |
| 90 | |
| 91 | it('behauptet nicht, die Freigabezeit sei nicht vollstaendig verteilt worden', () => { |
| 92 | const befund = befundZu({ severity: 'hinweis', code: UMGELEGT, message: 'Prüftext' }); |
| 93 | |
| 94 | expect(befund).toBeDefined(); |
| 95 | expect(befund?.title).not.toBe('Freigabezeit konnte nicht vollständig verteilt werden'); |
| 96 | expect(befund?.title).not.toBe('Hinweis aus dem Planaufbau'); |
| 97 | }); |
| 98 | |
| 99 | it('verlangt im Regelfall keine Pruefung von Freigabezeiten und Umlaufzeit', () => { |
| 100 | const befund = befundZu({ severity: 'hinweis', code: UMGELEGT, message: 'Prüftext' }); |
| 101 | |
| 102 | expect(befund?.suggestion).not.toBe( |
| 103 | 'Prüfen Sie die vorgegebenen Freigabezeiten und die Umlaufzeit; der Rest entsteht, wo ' + |
| 104 | 'beides nicht zusammenpasst.', |
| 105 | ); |
| 106 | expect(befund?.suggestion).not.toBe('Prüfen Sie die zugrunde liegenden Eingaben.'); |
| 107 | }); |
| 108 | |
| 109 | it('fuehrt die Umlegung unter dem Signalzeitenplan', () => { |
| 110 | // Sie ist eine Aussage ueber die Verteilung im Plan, keine ueber die |
| 111 | // Leistungsfaehigkeit und keine ueber die Zwischenzeiten. |
| 112 | const befund = befundZu({ severity: 'hinweis', code: UMGELEGT, message: 'Prüftext' }); |
| 113 | |
| 114 | expect(befund?.category).toBe('signalplan'); |
| 115 | }); |
| 116 | |
| 117 | it('laesst Ueberschrift und Rat des nicht verteilbaren Rests unveraendert', () => { |
| 118 | const befund = befundZu({ severity: 'warnung', code: REST, message: 'Prüftext' }); |
| 119 | |
| 120 | expect(befund?.title).toBe('Freigabezeit konnte nicht vollständig verteilt werden'); |
| 121 | expect(befund?.suggestion).toBe( |
| 122 | 'Prüfen Sie die vorgegebenen Freigabezeiten und die Umlaufzeit; der Rest entsteht, wo ' + |
| 123 | 'beides nicht zusammenpasst.', |
| 124 | ); |
| 125 | }); |
| 126 | }); |