lsa-planer

LSA-Planer Professional – Planungssoftware für Lichtsignalanlagen nach RiLSA 2015 und § 45 StVO. EUPL-1.2.

/ tests domain einfahrgeschwindigkeit.test.ts

6,8 KB Rohdatei
tests/domain/einfahrgeschwindigkeit.test.ts — 169 Zeilen
1 import { describe, expect, it } from 'vitest';
2 import { RILSA_DEFAULTS, SAFETY_FLOORS } from '@/domain/rilsa/constants';
3 import { computeIntergreen } from '@/domain/rilsa/intergreen';
4 import { resolveRilsaSettings, settingFields, type RilsaOverrides } from '@/domain/rilsa/settings';
5 import type { ClearingStream, EnteringStream, TrafficMode } from '@/domain/rilsa/types';
6
7 /*
8 * Befund 10, behoben in Fassung 5.10.0.
9 *
10 * tz = tue + tr - te. Eine NIEDRIGERE Einfahrgeschwindigkeit vergroessert te
11 * und verkuerzt damit die Zwischenzeit - die gefaehrliche Richtung. Bei jeder
12 * Raeumgeschwindigkeit riegelt das Programm diese Richtung ab (Feldschranke
13 * gegen SAFETY_FLOORS oder nachgelagerter Quervergleich in
14 * resolveRilsaSettings); die vier Einfahrgeschwindigkeitsfelder hatten weder
15 * das eine noch das andere. Kfz liess sich auf 5 m/s absenken - weniger als
16 * die Haelfte des Regelwerts von 11,1 m/s.
17 */
18
19 interface Einfahrfeld {
20 readonly key: keyof RilsaOverrides;
21 readonly mode: TrafficMode;
22 readonly regelwert: number;
23 /** Wert, den das Feld VOR der Behebung noch angenommen hat. */
24 readonly abgesenkt: number;
25 }
26
27 const EINFAHRFELDER: readonly Einfahrfeld[] = [
28 {
29 key: 'enteringSpeedKfz',
30 mode: 'kfz',
31 regelwert: RILSA_DEFAULTS.enteringSpeed.kfz,
32 abgesenkt: 5,
33 },
34 {
35 key: 'enteringSpeedRad',
36 mode: 'rad',
37 regelwert: RILSA_DEFAULTS.enteringSpeed.rad,
38 abgesenkt: 2,
39 },
40 {
41 key: 'enteringSpeedFuss',
42 mode: 'fuss',
43 regelwert: RILSA_DEFAULTS.enteringSpeed.fuss,
44 abgesenkt: 0.8,
45 },
46 {
47 key: 'enteringSpeedOepnv',
48 mode: 'oepnv',
49 regelwert: RILSA_DEFAULTS.enteringSpeed.oepnv,
50 abgesenkt: 5,
51 },
52 ];
53
54 const kfzRaeumt = (): ClearingStream => ({
55 mode: 'kfz',
56 movement: 'geradeaus',
57 clearingDistance: 22,
58 vehicleClass: 'pkw',
59 vZul: 50,
60 });
61
62 const kfzFaehrtEin = (overrides: Partial<EnteringStream> = {}): EnteringStream => ({
63 mode: 'kfz',
64 movement: 'geradeaus',
65 enteringDistance: 12,
66 ...overrides,
67 });
68
69 describe('Befund 10 - Einfahrgeschwindigkeit ist nach unten gesichert', () => {
70 it('hebt jede unter den Regelwert abgesenkte Vorgabe an und meldet sie als Fehler', () => {
71 for (const feld of EINFAHRFELDER) {
72 const { defaults, notes } = resolveRilsaSettings({ [feld.key]: feld.abgesenkt });
73 expect(defaults.enteringSpeed[feld.mode], feld.key).toBe(feld.regelwert);
74 expect(
75 notes.some(
76 (n) => n.code === `vorgabe-unterschritten:${feld.key}` && n.severity === 'fehler',
77 ),
78 feld.key,
79 ).toBe(true);
80 }
81 });
82
83 it('haelt die Untergrenze in SAFETY_FLOORS und nicht als Zahl im Feld', () => {
84 // Dieselbe Systematik wie bei den Raeumgeschwindigkeiten, nur spiegelbildlich:
85 // dort ist der Regelwert die Ober-, hier die Untergrenze.
86 expect(SAFETY_FLOORS.minEnteringSpeedKfz).toBe(RILSA_DEFAULTS.enteringSpeed.kfz);
87 expect(SAFETY_FLOORS.minEnteringSpeedRad).toBe(RILSA_DEFAULTS.enteringSpeed.rad);
88 expect(SAFETY_FLOORS.minEnteringSpeedFuss).toBe(RILSA_DEFAULTS.enteringSpeed.fuss);
89 expect(SAFETY_FLOORS.minEnteringSpeedOepnv).toBe(RILSA_DEFAULTS.enteringSpeed.oepnv);
90 });
91
92 it('begruendet die Schranke an jedem der vier Felder', () => {
93 const felder = settingFields();
94 for (const feld of EINFAHRFELDER) {
95 const beschreibung = felder.find((f) => f.key === feld.key);
96 expect(beschreibung, feld.key).toBeDefined();
97 expect(beschreibung!.min, feld.key).toBe(feld.regelwert);
98 expect(beschreibung!.schrankenBegruendung, feld.key).not.toBeNull();
99 expect(beschreibung!.schrankenBegruendung!, feld.key).toContain('verkürzt');
100 }
101 });
102
103 it('begruendet die Kappung nach oben mit der Obergrenze und nicht mit der Untergrenze', () => {
104 /*
105 * NACHTRAG (Fassung 5.10.0): begruendungFuer reicht eine
106 * Zeichenkette an BEIDE Schranken durch. Solange die vier Begruendungen
107 * Zeichenketten waren, endete die Meldung zur UEBERSCHRITTENEN Obergrenze
108 * mit dem Satz zur Untergrenze - ein falscher Satz in Pruefbericht und
109 * Planunterlage. Nach oben bleibt es bei der Plausibilitaetsschranke; eine
110 * Sicherheitsschranke ist dort nicht noetig.
111 */
112 const obergrenzen: readonly (readonly [keyof RilsaOverrides, number])[] = [
113 ['enteringSpeedKfz', 20],
114 ['enteringSpeedRad', 8],
115 ['enteringSpeedFuss', 2.5],
116 ['enteringSpeedOepnv', 20],
117 ];
118 for (const [key, obergrenze] of obergrenzen) {
119 const beschreibung = settingFields().find((f) => f.key === key);
120 expect(beschreibung, key).toBeDefined();
121 expect(beschreibung!.max, key).toBe(obergrenze);
122
123 const { defaults, notes } = resolveRilsaSettings({ [key]: obergrenze + 5 });
124 const meldung = notes.find((n) => n.code === `vorgabe-ueberschritten:${key}`);
125 expect(meldung, key).toBeDefined();
126 expect(meldung!.message, key).toContain('Der Wert wurde auf die Obergrenze begrenzt.');
127 expect(meldung!.message, key).not.toContain('Untergrenze');
128 expect(defaults.enteringSpeed, key).toBeDefined();
129 }
130
131 const { notes } = resolveRilsaSettings({ enteringSpeedKfz: 25 });
132 expect(notes.find((n) => n.code === 'vorgabe-ueberschritten:enteringSpeedKfz')!.message).toBe(
133 '"Einfahrgeschwindigkeit Kfz" wurde auf 25 m/s gesetzt, zulässig ist höchstens 20 m/s. ' +
134 'Der Wert wurde auf die Obergrenze begrenzt.',
135 );
136 });
137
138 it('laesst eine hoehere Einfahrgeschwindigkeit weiter zu - sie ist die sichere Richtung', () => {
139 const { defaults, notes } = resolveRilsaSettings({ enteringSpeedKfz: 13 });
140 expect(defaults.enteringSpeed.kfz).toBe(13);
141 expect(notes.filter((n) => n.severity === 'fehler')).toHaveLength(0);
142 });
143
144 it('laesst die Warnung je Konfliktbeziehung nicht durch eine abgesenkte Vorgabe verstummen', () => {
145 /*
146 * Zweite Wirkung des Befundes: resolveEnteringSpeed vergleicht die
147 * Handeingabe gegen defaults.enteringSpeed[mode] - also gegen den bereits
148 * aufgeloesten Kennwertsatz. Wanderte die Vorgabe auf 5 m/s mit, war eine
149 * Handeingabe von 5 m/s kein Unterschreiten mehr, und die Warnung blieb
150 * aus. Mit der Untergrenze kann der Massstab nicht mehr mitwandern.
151 */
152 const { defaults } = resolveRilsaSettings({ enteringSpeedKfz: 5 });
153 const ergebnis = computeIntergreen(
154 kfzRaeumt(),
155 kfzFaehrtEin({ enteringSpeedOverride: 5 }),
156 defaults,
157 );
158 expect(ergebnis.notes.some((n) => n.code === 'einfahrgeschwindigkeit-unter-regelwert')).toBe(
159 true,
160 );
161 });
162
163 it('verkuerzt keine Zwischenzeit mehr ueber die Vorgabenverwaltung', () => {
164 const mitRegelwert = computeIntergreen(kfzRaeumt(), kfzFaehrtEin(), RILSA_DEFAULTS);
165 const { defaults } = resolveRilsaSettings({ enteringSpeedKfz: 5 });
166 const mitVorgabe = computeIntergreen(kfzRaeumt(), kfzFaehrtEin(), defaults);
167 expect(mitVorgabe.intergreen).toBe(mitRegelwert.intergreen);
168 });
169 });