lsa-planer

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

/ tests export reststauNachrechnen.test.ts

4,0 KB Rohdatei
tests/export/reststauNachrechnen.test.ts — 95 Zeilen
1 import { inflateSync } from 'node:zlib';
2 import { describe, expect, it } from 'vitest';
3 import { buildProjectPdf, DEFAULT_PDF_OPTIONS } from '@/services/export/pdf';
4 import { buildSignalPlan } from '@/domain/plan/signalPlan';
5 import { validateProject } from '@/domain/validation';
6 import { createStandardIntersectionProject } from '@/domain/model/factory';
7 import { roundTo } from '@/domain/units';
8 import { toWinAnsi } from '@/render/pdfSurface';
9
10 /*
11 * BEFUND 50 (Fassung 5.11.0): Die Tabelle "Leistungsfaehigkeit - Rechenweg
12 * Wartezeit" druckt NGE, C und tW,R nebeneinander, und der Formelabsatz
13 * unmittelbar darunter sagte als einzige Einschraenkung "Angaben mit
14 * Zwischenrundung auf die gedruckten Stellen".
15 *
16 * Was der Pruefer sonst erlebt: Er rechnet die Zeile nach - tW,R = NGE * 3600 /
17 * C - und kommt auf eine andere Zahl als die gedruckte. Im Regelbeispiel geht
18 * das an zwei von vier Kfz-Zeilen nicht auf (K1: 5,7 gegen gedruckte 5,6;
19 * K4: 3,8 gegen 3,7). Der Grund ist begruendet und bleibt: delay.ts bildet
20 * tW,R als Differenz tW - tW,G auf den AUSGEGEBENEN Ziffern, damit
21 * tW,G + tW,R die gedruckte Gesamtwartezeit ergibt. Ungesagt blieb er
22 * trotzdem - und der Kopfkommentar desselben Abschnitts verlangt: "Was
23 * gedruckt wird, muss sich aus den gedruckten Groessen nachrechnen lassen."
24 *
25 * Behoben wird auf der Druckseite, nicht in delay.ts: Die Differenzbildung
26 * selbst ist durch tests/domain/hbsWartezeit.test.ts mit eigener Begruendung
27 * festgehalten.
28 */
29
30 const FEST = new Date('2026-01-01T12:00:00Z');
31
32 /** Sichtbaren Text aus dem PDF lesen; die Inhaltsstroeme sind komprimiert. */
33 function pdfText(bytes: Uint8Array): string {
34 const roh = new TextDecoder('latin1').decode(bytes);
35 const teile: string[] = [];
36 const suche = /stream\r?\n/g;
37 let treffer: RegExpExecArray | null;
38
39 while ((treffer = suche.exec(roh)) !== null) {
40 const start = treffer.index + treffer[0].length;
41 const ende = roh.indexOf('endstream', start);
42 if (ende < 0) continue;
43 let inhalt: string;
44 try {
45 inhalt = inflateSync(Buffer.from(roh.slice(start, ende), 'latin1')).toString('latin1');
46 } catch {
47 continue;
48 }
49 for (const t of inhalt.matchAll(/\(((?:[^()\\]|\\.)*)\)\s*Tj/g)) {
50 teile.push(t[1]!.replace(/\\([()\\])/g, '$1'));
51 }
52 }
53 return teile.join(' ').replace(/\s+/g, ' ');
54 }
55
56 const gedruckt = (text: string): string => toWinAnsi(text).replace(/\s+/g, ' ');
57
58 const projekt = createStandardIntersectionProject('Hauptstrasse / Bahnhofstrasse', FEST);
59 const plan = buildSignalPlan(projekt);
60
61 describe('Befund 50 - Reststauanteil im Rechenweg der Wartezeit', () => {
62 it('Vorbedingung: die gedruckte Spalte tW,R weicht von NGE * 3600 / C ab', () => {
63 // Ohne diese Abweichung gaebe es nichts zu erklaeren; der Zusatz waere
64 // dann eine Behauptung ueber einen Fall, den es nicht gibt.
65 const abweichend = plan.groups.filter((group) => {
66 const delay = group.delay;
67 const kapazitaet = group.capacity;
68 if (delay === null || kapazitaet === null) return false;
69 const nge = delay.rechenweg.reststau;
70 if (nge === null) return false;
71 return roundTo((nge * 3600) / kapazitaet.capacity, 1) !== roundTo(delay.incrementalDelay, 1);
72 });
73
74 expect(
75 abweichend.map((g) => g.name),
76 'im Regelbeispiel gehen zwei von vier Kfz-Zeilen nicht auf',
77 ).not.toHaveLength(0);
78 });
79
80 it('sagt im Formelabsatz, dass tW,R als Differenz gebildet ist', () => {
81 const bericht = validateProject(projekt, plan, FEST);
82 const text = pdfText(buildProjectPdf(projekt, plan, bericht, DEFAULT_PDF_OPTIONS, FEST));
83
84 expect(text, 'Vorbedingung: der Abschnitt steht in der Regelausgabe').toContain(
85 gedruckt('tW,R = NGE · 3600 / C'),
86 );
87 expect(text).toContain(
88 gedruckt(
89 'Die Spalte tW,R ist nicht aus NGE und C gerundet, sondern als Differenz tW - tW,G auf ' +
90 'den ausgegebenen Ziffern gebildet, damit tW,G + tW,R die gedruckte Gesamtwartezeit ' +
91 'ergibt; gegenüber NGE · 3600 / C kann sie deshalb um bis zu 0,1 s abweichen.',
92 ),
93 );
94 });
95 });