lsa-planer

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

/ tests app phasenSperre.test.ts

3,5 KB Rohdatei
tests/app/phasenSperre.test.ts — 97 Zeilen
1 import { describe, expect, it } from 'vitest';
2 import { feindlichePartnerInPhase, togglePhaseGroup } from '@/app/actions';
3 import { createStandardIntersectionProject } from '@/domain/model/factory';
4 import type { Project } from '@/domain/model/project';
5
6 /**
7 * Befund B10.
8 *
9 * Die Vertraeglichkeitsansicht verspricht: "Das Programm laesst dabei nur
10 * vertraegliche Gruppen in dieselbe Phase." Bis zu diesem Befund fuegte
11 * togglePhaseGroup jede Gruppe ungeprueft hinzu - das Versprechen war falsch,
12 * und wer ihm vertraute, hielt die rote Markierung fuer eine blosse
13 * Hervorhebung. Jetzt lehnt die Aktion feindliche Zuordnungen ab.
14 */
15
16 const FIXED_DATE = new Date('2026-01-01T00:00:00Z');
17
18 /** Regelknotenpunkt: K1/K2 (Nord/Sued) vertraeglich, K1/K3 (Nord/Ost) feindlich. */
19 function projekt(): Project {
20 return createStandardIntersectionProject('Prueffall', FIXED_DATE);
21 }
22
23 function gruppe(project: Project, name: string): string {
24 const found = project.signalGroups.find((g) => g.name === name);
25 if (!found) throw new Error(`Signalgruppe ${name} fehlt im Prueffall`);
26 return found.id;
27 }
28
29 function phaseMit(project: Project, name: string): { projekt: Project; phaseId: string } {
30 const phaseId = project.phases[0]!.id;
31 const leer: Project = {
32 ...project,
33 phases: project.phases.map((p, i) => (i === 0 ? { ...p, signalGroupIds: [] } : p)),
34 };
35 return { projekt: togglePhaseGroup(leer, phaseId, gruppe(project, name)), phaseId };
36 }
37
38 describe('Phasen-Sperre fuer feindliche Signalgruppen', () => {
39 it('lehnt die Zuordnung einer feindlichen Gruppe ab', () => {
40 const basis = projekt();
41 const { projekt: mitK1, phaseId } = phaseMit(basis, 'K1');
42 expect(
43 basis.conflicts.some(
44 (c) =>
45 (c.fromId === gruppe(basis, 'K1') && c.toId === gruppe(basis, 'K3')) ||
46 (c.fromId === gruppe(basis, 'K3') && c.toId === gruppe(basis, 'K1')),
47 ),
48 ).toBe(true);
49
50 const danach = togglePhaseGroup(mitK1, phaseId, gruppe(basis, 'K3'));
51
52 expect(danach).toBe(mitK1);
53 expect(danach.phases.find((p) => p.id === phaseId)!.signalGroupIds).toEqual([
54 gruppe(basis, 'K1'),
55 ]);
56 });
57
58 it('laesst eine vertraegliche Gruppe zu', () => {
59 const basis = projekt();
60 const { projekt: mitK1, phaseId } = phaseMit(basis, 'K1');
61
62 const danach = togglePhaseGroup(mitK1, phaseId, gruppe(basis, 'K2'));
63
64 expect(danach.phases.find((p) => p.id === phaseId)!.signalGroupIds).toContain(
65 gruppe(basis, 'K2'),
66 );
67 });
68
69 it('erlaubt das Entfernen auch bei einem aus Altdaten geladenen Konfliktpaar', () => {
70 // Altdaten koennen feindliche Paare in einer Phase tragen; der Rueckweg
71 // heraus darf nie gesperrt sein.
72 const basis = projekt();
73 const phaseId = basis.phases[0]!.id;
74 const altdaten: Project = {
75 ...basis,
76 phases: basis.phases.map((p, i) =>
77 i === 0 ? { ...p, signalGroupIds: [gruppe(basis, 'K1'), gruppe(basis, 'K3')] } : p,
78 ),
79 };
80
81 const danach = togglePhaseGroup(altdaten, phaseId, gruppe(basis, 'K3'));
82
83 expect(danach.phases.find((p) => p.id === phaseId)!.signalGroupIds).toEqual([
84 gruppe(basis, 'K1'),
85 ]);
86 });
87
88 it('nennt die feindlichen Partner fuer die Meldung der Oberflaeche', () => {
89 const basis = projekt();
90 const { projekt: mitK1, phaseId } = phaseMit(basis, 'K1');
91
92 const partner = feindlichePartnerInPhase(mitK1, phaseId, gruppe(basis, 'K3'));
93
94 expect(partner.map((g) => g.name)).toEqual(['K1']);
95 expect(feindlichePartnerInPhase(mitK1, phaseId, gruppe(basis, 'K2'))).toHaveLength(0);
96 });
97 });