lsa-planer

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

/ tests domain gegenrichtungUndSkala.test.ts

4,0 KB Rohdatei
tests/domain/gegenrichtungUndSkala.test.ts — 99 Zeilen
1 import { describe, expect, it } from 'vitest';
2 import { validateProject } from '@/domain/validation/engine';
3 import { buildSignalPlan } from '@/domain/plan/signalPlan';
4 import { TrafficSimulation } from '@/domain/simulation/simulation';
5 import { serviceLevelFor } from '@/domain/rilsa/delay';
6 import { createStandardIntersectionProject } from '@/domain/model/factory';
7 import type { Project } from '@/domain/model/project';
8
9 const STICHTAG = new Date('2026-01-01T00:00:00Z');
10
11 function vollstaendig(name: string): Project {
12 const base = createStandardIntersectionProject(name, STICHTAG);
13 return {
14 ...base,
15 meta: {
16 ...base.meta,
17 projectNumber: 'VP-2026-001',
18 client: 'Stadt Musterhausen',
19 planner: 'O. Willerding',
20 location: name,
21 },
22 };
23 }
24
25 describe('Fehlende Gegenrichtung einer Konfliktbeziehung', () => {
26 /*
27 * Das war eine Warnung und liess den Export offen. Ohne erfasste
28 * Gegenrichtung gibt es keine Zwischenzeit - und damit auch keinen Sollwert,
29 * gegen den die Abstandspruefung des fertigen Plans messen koennte. Die
30 * fehlende Haelfte ist die einzige Stelle, an der ein feindliches Paar
31 * voellig ungesichert bleibt.
32 */
33 it('sperrt den Export', () => {
34 const roh = vollstaendig('Gegenrichtung');
35 const [k1, , k3] = roh.signalGroups;
36 const projekt: Project = {
37 ...roh,
38 conflicts: roh.conflicts.filter((c) => !(c.fromId === k3!.id && c.toId === k1!.id)),
39 };
40
41 const bericht = validateProject(projekt, buildSignalPlan(projekt), STICHTAG);
42 const befund = bericht.findings.find((f) => f.rule === 'konflikte.gegenrichtung-fehlt');
43
44 expect(befund).toBeDefined();
45 expect(befund!.severity).toBe('fehler');
46 expect(befund!.title).toContain('K1 nach K3');
47 expect(befund!.message).toContain('K3');
48 expect(bericht.exportBlocked).toBe(true);
49 });
50
51 it('schweigt beim Regelknotenpunkt, in dem jede Beziehung beidseitig erfasst ist', () => {
52 const bericht = validateProject(vollstaendig('Regelfall'), undefined, STICHTAG);
53 expect(bericht.findings.some((f) => f.rule === 'konflikte.gegenrichtung-fehlt')).toBe(false);
54 expect(bericht.findings.filter((f) => f.severity === 'fehler')).toHaveLength(0);
55 });
56 });
57
58 describe('Bewertungsskala in der Simulation', () => {
59 /*
60 * serviceLevelFor wurde ohne Skala gerufen und fiel damit auf HBS zurueck,
61 * waehrend der Signalzeitenplan die eingestellte Skala korrekt weiterreicht.
62 * Dieselbe Wartezeit erhielt in der Simulation eine andere Qualitaetsstufe
63 * als in der Leistungsfaehigkeit - und im Ausdruck stand daneben "Bewertung
64 * nach HCM".
65 */
66 function laufen(skala: 'HBS' | 'HCM'): ReturnType<TrafficSimulation['snapshot']> {
67 const roh = vollstaendig('Simulation');
68 const projekt: Project = {
69 ...roh,
70 settings: { ...roh.settings, serviceLevelScale: skala },
71 };
72 const sim = new TrafficSimulation(buildSignalPlan(projekt), projekt, { seed: 42 });
73 sim.advance(600);
74 return sim.snapshot();
75 }
76
77 it('bewertet nach der eingestellten Skala', () => {
78 for (const skala of ['HBS', 'HCM'] as const) {
79 const stand = laufen(skala);
80 expect(stand.overallServiceLevel.scale, skala).toBe(skala);
81 for (const gruppe of stand.groups) {
82 expect(gruppe.serviceLevel.scale, `${skala} / ${gruppe.name}`).toBe(skala);
83 // Die Stufe muss zu Wartezeit UND Skala passen, nicht nur die
84 // Beschriftung der Skala.
85 // (Ohne Ueberlastung entscheidet die Wartezeit allein; die Gruppen
86 // dieses Projekts sind nicht ueberlastet.)
87 expect(gruppe.serviceLevel.grade, `${skala} / ${gruppe.name}`).toBe(
88 serviceLevelFor(gruppe.averageDelay, skala)?.grade,
89 );
90 }
91 }
92 });
93
94 it('kommt bei derselben Wartezeit je nach Skala zu verschiedenen Stufen', () => {
95 // Ohne diesen Nachweis koennte die Skala mitgefuehrt und doch wirkungslos
96 // sein. 31,9 s sind nach HBS Stufe B, nach HCM Stufe C.
97 expect(serviceLevelFor(31.9, 'HBS')?.grade).not.toBe(serviceLevelFor(31.9, 'HCM')?.grade);
98 });
99 });