lsa-planer

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

/ tests export grosseAnlage.test.ts

3,6 KB Rohdatei
tests/export/grosseAnlage.test.ts — 100 Zeilen
1 import { describe, expect, it } from 'vitest';
2 import { buildProjectPdf, DEFAULT_PDF_OPTIONS, type PdfOptions } from '@/services/export/pdf';
3 import { buildSignalPlan } from '@/domain/plan/signalPlan';
4 import { validateProject } from '@/domain/validation';
5 import {
6 createArm,
7 createEmptyProject,
8 createPhase,
9 createSignalGroup,
10 } from '@/domain/model/factory';
11 import type { Project, SignalGroup } from '@/domain/model/project';
12
13 /*
14 * BEFUND 39 (Fassung 5.11.0): Die Zwischenzeitenmatrix breitete ihre n-mal-n
15 * Zellen als Argumentliste in Math.max aus.
16 *
17 * Was der Anwender sonst erlebt: Er liest eine Projektdatei mit 356 oder mehr
18 * Signalgruppen ein - weder `parseSignalGroups` noch `addSignalGroup` kennen
19 * eine Obergrenze - und erzeugt die Planunterlage. V8 nimmt nur rund 125.000
20 * Argumente an; darueber bricht der Aufruf mit "RangeError: Maximum call stack
21 * size exceeded" ab. In der Ansicht "Ausgabe" steht dann nur "Das PDF konnte
22 * nicht erzeugt werden: Maximum call stack size exceeded", und es entsteht
23 * keine Unterlage - auch der Pruefbericht nicht.
24 *
25 * Betroffen sind beide Satzarten, denn beide breiten `zellen.flat()` aus:
26 * `matrixPasstAufEinBlatt` bei eindeutigen Namen und `matrixSatz` bei doppelten
27 * (dort greift die fruehe Rueckgabe aus `matrixMarkenSindEindeutig`).
28 */
29
30 const FEST = new Date('2026-01-01T12:00:00Z');
31
32 /** 355^2 = 126.025 Werte - gerade oberhalb der gemessenen Schranke von V8. */
33 const GRUPPEN = 356;
34
35 const NUR_MATRIX: PdfOptions = {
36 ...DEFAULT_PDF_OPTIONS,
37 includeSignalGroups: false,
38 includePhases: false,
39 includePlan: false,
40 includePerformance: false,
41 includeReport: false,
42 includeCalculationDetails: false,
43 includeSources: false,
44 };
45
46 /**
47 * Eine grosse Anlage ohne jede Konfliktbeziehung: Die Matrix ist voll besetzt
48 * mit dem Punkt fuer "vertraeglich" - n^2 Zellen, aber nichts zu rechnen.
49 */
50 function grosseAnlage(n: number, name: (i: number) => string): Project {
51 const basis = createEmptyProject('Grosse Anlage', FEST, 'knotenpunkt');
52 const arme = ['Nord', 'Ost', 'Süd', 'West'].map((r) => createArm(r, r, 2, 50));
53
54 const groups: SignalGroup[] = [];
55 for (let i = 0; i < n; i += 1) {
56 groups.push(
57 createSignalGroup({
58 name: name(i),
59 mode: 'kfz',
60 armId: arme[i % 4]?.id ?? null,
61 index: i,
62 }),
63 );
64 }
65
66 // Alle Gruppen in einer Phase: Sonst meldet die Pruefung "keiner Phase
67 // zugeordnet" und die Ausgabe waere in der Oberflaeche gesperrt.
68 const phase = createPhase(
69 'Phase 1',
70 groups.map((g) => g.id),
71 );
72
73 return {
74 ...basis,
75 intersection: { ...basis.intersection, arms: arme },
76 signalGroups: groups,
77 conflicts: [],
78 phases: [phase],
79 program: { ...basis.program, phaseOrder: [phase.id] },
80 };
81 }
82
83 function unterlage(project: Project): Uint8Array {
84 const plan = buildSignalPlan(project);
85 return buildProjectPdf(project, plan, validateProject(project, plan, FEST), NUR_MATRIX, FEST);
86 }
87
88 describe('Befund 39 - Zwischenzeitenmatrix bei sehr vielen Signalgruppen', () => {
89 it(`erzeugt die Unterlage bei ${GRUPPEN} Signalgruppen mit eindeutigen Namen`, () => {
90 const bytes = unterlage(grosseAnlage(GRUPPEN, (i) => `K${i + 1}`));
91 expect(bytes.byteLength).toBeGreaterThan(0);
92 }, 120_000);
93
94 it(`erzeugt die Unterlage bei ${GRUPPEN} Signalgruppen mit doppelten Namen`, () => {
95 // Doppelte Namen fuehren ueber matrixMarkenSindEindeutig in den
96 // Ausschnittsatz - dort steht die zweite Ausbreitung.
97 const bytes = unterlage(grosseAnlage(GRUPPEN, () => 'K'));
98 expect(bytes.byteLength).toBeGreaterThan(0);
99 }, 120_000);
100 });