lsa-planer

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

/ tests export fahrstreifenkomma.test.ts

3,4 KB Rohdatei
tests/export/fahrstreifenkomma.test.ts — 78 Zeilen
1 import { describe, expect, it } from 'vitest';
2 import { signalGroupsCsv } from '@/services/export/csv';
3 import { buildSignalPlan } from '@/domain/plan/signalPlan';
4 import { createStandardIntersectionProject } from '@/domain/model/factory';
5 import type { Project } from '@/domain/model/project';
6
7 /*
8 * Befund 55 zur Fassung 5.9.0.
9 *
10 * Der Kopfkommentar von src/services/export/csv.ts sagt zu: "Trennzeichen ist
11 * das Semikolon und Dezimaltrennzeichen das Komma - so oeffnet Excel in
12 * deutscher Einstellung die Datei ohne Importdialog." Jede Zahl der Tabelle
13 * laeuft ueber src/ui/format.ts, nur die Fahrstreifenzahl ging als
14 * `String(group.lanes)` hinaus.
15 *
16 * `num()` in schema.ts rundet `lanes` seit der Fassung 5.10.0 auf eine
17 * ganze Zahl AB und meldet die Ersetzung (`ganzzahlAbrunden`; Wache
18 * tests/domain/fahrstreifenzahl.test.ts) - aus einer Projektdatei kommt
19 * eine 2,5 also nicht mehr durch. Der Fall laesst sich hier trotzdem bauen:
20 * Diese Datei setzt das Projekt unmittelbar zusammen, ohne `parseProject`, und
21 * `SignalGroup.lanes` traegt im Typ keine Ganzzahlschranke. Bewacht wird die
22 * Schreibweise der Zelle und nicht der Weg, auf dem der Wert entsteht: In
23 * einer deutsch eingestellten Tabellenkalkulation ist der Punkt Tausender-
24 * bzw. Datumstrenner - die Zelle wird dort nicht als Zahl gelesen.
25 *
26 * Gegen den Altstand schlaegt der erste Fall fehl; der zweite haelt fest, dass
27 * sich an ganzzahligen Werten nichts aendert.
28 */
29
30 const STICHTAG = new Date('2026-01-01T12:00:00Z');
31
32 function tabelle(csv: string): { kopf: string[]; zeilen: string[][] } {
33 const zerlege = (zeile: string): string[] =>
34 (zeile.match(/("([^"]|"")*"|[^;]*)(;|$)/g) ?? []).map((feld) =>
35 feld.replace(/;$/, '').replace(/^"|"$/g, '').replace(/""/g, '"'),
36 );
37 const [kopfzeile, ...rest] = csv.split('\r\n');
38 return {
39 kopf: zerlege((kopfzeile ?? '').replace(/^/, '')),
40 zeilen: rest.filter((z) => z.length > 0).map(zerlege),
41 };
42 }
43
44 /** Knotenpunkt, dessen erste Signalgruppe eine gebrochene Fahrstreifenzahl traegt. */
45 function mitGebrochenerFahrstreifenzahl(): Project {
46 const basis = createStandardIntersectionProject('Fahrstreifen', STICHTAG);
47 return {
48 ...basis,
49 signalGroups: basis.signalGroups.map((g, index) => (index === 0 ? { ...g, lanes: 2.5 } : g)),
50 };
51 }
52
53 describe('Befund 55 - die Fahrstreifenspalte trägt das deutsche Dezimalkomma', () => {
54 it('schreibt 2,5 statt 2.5', () => {
55 const projekt = mitGebrochenerFahrstreifenzahl();
56 const { kopf, zeilen } = tabelle(signalGroupsCsv(projekt, buildSignalPlan(projekt)));
57 const spalte = kopf.indexOf('Fahrstreifen');
58 const zeile = zeilen.find((z) => z[0] === projekt.signalGroups[0]!.name)!;
59
60 expect(spalte).toBeGreaterThanOrEqual(0);
61 expect(zeile[spalte]).toBe('2,5');
62 // Kein englischer Dezimalpunkt - die Zusage des Kopfkommentars gilt auch
63 // fuer diese Zelle. (Der Punkt als Tausendertrenner steht anderswo
64 // absichtlich, etwa in "4.784,69".)
65 expect(zeile[spalte]).not.toContain('.');
66 });
67
68 it('lässt ganze Fahrstreifenzahlen unverändert', () => {
69 const projekt = createStandardIntersectionProject('Fahrstreifen', STICHTAG);
70 const { kopf, zeilen } = tabelle(signalGroupsCsv(projekt, buildSignalPlan(projekt)));
71 const spalte = kopf.indexOf('Fahrstreifen');
72
73 for (const gruppe of projekt.signalGroups) {
74 const zeile = zeilen.find((z) => z[0] === gruppe.name)!;
75 expect(zeile[spalte], gruppe.name).toBe(String(gruppe.lanes));
76 }
77 });
78 });