lsa-planer

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

/ tests tools werkbanktexte.test.ts

9,5 KB Rohdatei
tests/tools/werkbanktexte.test.ts — 181 Zeilen
1 import { readFileSync } from 'node:fs';
2 import { describe, expect, it } from 'vitest';
3
4 /*
5 * Befunde 66, 67 und 38 zur Fassung 5.10.0.
6 *
7 * Drei Angaben der Werkbank, die sich am Baum nachmessen lassen und deshalb
8 * nicht als blosser Fliesstext stehenbleiben duerfen:
9 *
10 * 66. `eslint.config.mjs` begruendet, welche Warnungen bewusst stehen
11 * bleiben, und bezifferte `no-unnecessary-type-assertion` mit "67 Faelle,
12 * ueberwiegend in tests/". Gemessen mit `npx eslint . -f json` sind es 36
13 * Warnungen insgesamt - 31 no-unnecessary-condition, 4
14 * switch-exhaustiveness-check und genau 1 no-unnecessary-type-assertion,
15 * und die steht in `electron/karte.ts`, nicht in tests/. Der Kommentar
16 * widerlegt sich sogar ohne Linterlauf: 67 plus 4 sind 71, waehrend
17 * als offener Rueckstand 36 vermerkt waren - unter Verweis auf ebendiese
18 * Begruendung. Dieselbe Grosszuegigkeit darf die neue Begruendung nicht
19 * wiederholen: Von den 31 Faellen liegt einer in `e2e/rauchtest.spec.ts`.
20 * `e2e/` faellt nicht unter den Ausnahmeblock fuer `tests/**`, gehoert
21 * aber ebenso wenig zum Programm - "vollstaendig im Programm" waere um
22 * einen Fall zu weit.
23 *
24 * NACHGEZOGEN NACH 5.16.0: Diese Fallzahlen gibt es nicht mehr, und die
25 * vier Faelle, die sie nachrechneten, ebenso wenig. Der geduldete
26 * Rueckstand ist abgetragen - die Regeln melden Fehler, jede beanstandete
27 * Zeile traegt ihren eigenen Ausnahmevermerk samt Grund, `npm run lint`
28 * laeuft mit `--max-warnings 0`. Der Befund bleibt hier als Bericht
29 * stehen, weil er der Grund ist, warum es diese Datei gibt; was von ihm
30 * dauerhaft galt - der Ausnahmeblock gilt fuer tests/ und nicht fuer
31 * e2e/ -, prueft der Block unten weiter. Die Gegenrichtung haelt
32 * `tests/tools/linterregelwerk.test.ts` fest, den Zustand
33 * selbst `tests/tools/linterRueckstand.test.ts`.
34 *
35 * 67. `e2e/rauchtest.spec.ts` begruendete seine Daseinsberechtigung mit "Die
36 * 1670 Modultests" - der Stand bei Einfuehrung der Datei. Der Baum steht
37 * bei einem Vielfachen. Eine Wache auf die richtige Zahl waere der
38 * falsche Weg: Die Zahl der Faelle laesst sich statisch nicht ermitteln.
39 * Bewacht wird deshalb, dass dort ueberhaupt keine Zahl mehr steht - was keine
40 * Zahl nennt, kann auch nicht stumm veralten.
41 *
42 * 38. `.githooks/pre-commit` setzt voraus, dass jemand einmal
43 * `git config core.hooksPath .githooks` ausgefuehrt hat. Dieser Eintrag
44 * steht in `.git/config` und damit ausserhalb des Baumes; `git clone`,
45 * `git worktree add` und ein frisches Auschecken fuehren ihn nicht mit.
46 * Solange das Projekt den Haken nicht selbst einrichtet, muss die Datei
47 * das sagen, statt die Einrichtung als geschehen darzustellen.
48 *
49 * S4. Derselbe Kopf sagt unbedingt zu, der Haken fange ab, "was sich sonst
50 * erst beim Anwender zeigt". Die vier Stufen der Schnellstufe lesen aber
51 * die Dateien so, wie sie auf der Platte liegen, nicht so, wie sie im
52 * Bereitstellungsbereich stehen. Bei teilweiser Bereitstellung beurteilt
53 * der Lauf einen anderen Inhalt als den, der in den Commit geht - in
54 * beide Richtungen. Ein Wegwerf-Arbeitsbaum je Commit ist die falsche
55 * Antwort darauf: Er verlangt je Commit ein eigenes Verzeichnis samt
56 * node_modules, und das faellt bei JEDEM Commit an. Die Grenze gehoert
57 * aber benannt. NACHGEZOGEN AM 07.09.2026: Hier stand als Begruendung,
58 * der Wegwerfbaum sprenge die "im selben Kopf zugesagten etwa zwanzig
59 * Sekunden". Diese Zusage steht dort nicht mehr - der Haken nennt
60 * seit der Fassung 5.16.0 gar keine Laufzeit mehr, weil sie um das
61 * Vierfache daneben lag. Ein Kommentar, der eine gestrichene Stelle
62 * zitiert, ist
63 * selbst eine falsche Angabe.
64 *
65 * WARUM KEIN LINTERLAUF IM TESTFALL: `eslint .` braucht einen eigenen Lauf ueber
66 * den ganzen Baum, und ein Testfall darf den nicht anwerfen. Das gilt
67 * unveraendert - nur ist der Widerspruch, den es ohne Linterlauf nachzumessen
68 * galt, mit den Fallzahlen weggefallen. `gate:schnell` faehrt den Linter
69 * ohnehin bei jedem Commit, und seit `--max-warnings 0` haelt schon eine
70 * einzige Warnung den Lauf an.
71 */
72
73 const LINTERREGELWERK = readFileSync('eslint.config.mjs', 'utf8');
74 const RAUCHTEST = readFileSync('e2e/rauchtest.spec.ts', 'utf8');
75 const HAKEN = readFileSync('.githooks/pre-commit', 'utf8');
76 /** Kommentartext des Hakens ohne Rautenzeichen und Zeilenumbrueche - Saetze stehen dort umbrochen. */
77 const HAKENTEXT = HAKEN.replace(/^#+ ?/gm, '').replace(/\s+/g, ' ');
78 const PAKET = JSON.parse(readFileSync('package.json', 'utf8')) as {
79 scripts?: Record<string, string>;
80 };
81
82 describe('eslint.config.mjs - der Ausnahmeblock fuer tests/', () => {
83 /*
84 * WAS HIER FRUEHER STAND: vier weitere Faelle, die die Fallzahlen des
85 * Begruendungsblocks nachrechneten - Summe gegen die vermerkte Zahl,
86 * Aufteilung Programm gegen Rauchtest, eine Fallzahl je Regel auf 'warn'.
87 * Alle vier setzten voraus, dass es einen geduldeten Rueckstand gibt. Den
88 * gibt es nicht mehr: Die Regeln melden Fehler, jede beanstandete Zeile
89 * traegt ihren eigenen Ausnahmevermerk samt Grund, und `npm run lint` laeuft
90 * mit `--max-warnings 0`. Zahlen, die nicht mehr dastehen, lassen sich nicht
91 * nachrechnen.
92 *
93 * WAS BLEIBT, weil es vom Rueckstand unabhaengig ist: Der Ausnahmeblock fuer
94 * `tests/` gilt fuer tests/ und fuer nichts sonst. Der eine Fall in
95 * `e2e/rauchtest.spec.ts` gehoert zum Programm - ihn stillschweigend
96 * mitzunehmen waere dieselbe zu grosszuegige Selbstauskunft, die Befund 66
97 * abstellen sollte.
98 *
99 * Die Gegenrichtung - keine der drei Regeln wird woanders abgeschwaecht -
100 * haelt `tests/tools/linterregelwerk.test.ts` fest.
101 */
102 it('schaltet no-unnecessary-condition fuer tests/ ab', () => {
103 const block = LINTERREGELWERK.slice(LINTERREGELWERK.lastIndexOf("files: ['tests/**/*.ts']"));
104 expect(block, 'Block fuer tests/ nicht gefunden').not.toBe('');
105 expect(block).toContain("'@typescript-eslint/no-unnecessary-condition': 'off'");
106 });
107
108 it('nimmt e2e/ von der Regel nicht aus', () => {
109 // Der Dateiabschnitt des Blocks, der die Regel abschaltet - nicht der des
110 // Blocks, der sie setzt: `e2e/**/*.ts` steht dort sehr wohl, aber unter
111 // den typgepruefen Ordnern, nicht unter den Ausnahmen.
112 const aus = LINTERREGELWERK.indexOf("'@typescript-eslint/no-unnecessary-condition': 'off'");
113 expect(aus, 'Ausnahmeblock nicht gefunden').toBeGreaterThan(0);
114 const ausnahme = LINTERREGELWERK.slice(LINTERREGELWERK.lastIndexOf('files:', aus), aus);
115 expect(ausnahme, 'Ausnahme gilt fuer tests/').toContain('tests/**/*.ts');
116 expect(ausnahme, 'Ausnahme darf e2e/ nicht mitnehmen').not.toContain('e2e');
117 });
118 });
119
120 describe('e2e/rauchtest.spec.ts - der Kopf', () => {
121 it('nennt keine Zahl von Modultests', () => {
122 // Ziffern samt Tausendertrennern - auch schmales und geschuetztes
123 // Leerzeichen, mit denen eine Zahl geschrieben sein koennte.
124 const zahl = /\d[\d.,\u202f\u00a0 ]*Modultests/.exec(RAUCHTEST);
125 expect(zahl?.[0] ?? null, 'Zahlenangabe vor "Modultests"').toBeNull();
126 });
127
128 it('behaelt die Abgrenzung, die den Rauchtest begruendet', () => {
129 // Ohne die Zahl muss der Satz weiter tragen: Die Modultests starten das
130 // Programm nicht, dieser Test tut es.
131 const kopf = RAUCHTEST.replace(/\s+/g, ' ');
132 expect(kopf).toContain('Modultests pruefen Fachlogik, Ausdruck und Oberflaechenfunktionen');
133 expect(kopf).toContain('aber keiner von ihnen startet das Programm');
134 });
135 });
136
137 describe('.githooks/pre-commit - die Einrichtung', () => {
138 /** Richtet ein Skript aus package.json den Haken selbsttaetig ein? */
139 function richtetSelbstEin(): boolean {
140 return Object.values(PAKET.scripts ?? {}).some((s) => s.includes('core.hooksPath'));
141 }
142
143 const WARNUNG = 'Dieser Befehl gehoert einmal in JEDE Arbeitskopie';
144 const KEINE_SELBSTEINRICHTUNG = 'Das Projekt fuehrt ihn nirgends selbsttaetig aus.';
145
146 it('sagt der Haken, wie es um seine Einrichtung wirklich steht', () => {
147 if (richtetSelbstEin()) {
148 // Sobald package.json den Haken einrichtet, waere der Vorbehalt falsch.
149 expect(HAKENTEXT, 'Vorbehalt trotz Selbsteinrichtung').not.toContain(KEINE_SELBSTEINRICHTUNG);
150 return;
151 }
152 expect(HAKENTEXT, 'Hinweis, dass der Befehl je Arbeitskopie faellig ist').toContain(WARNUNG);
153 expect(HAKENTEXT, 'Hinweis, dass ihn nichts selbsttaetig ausfuehrt').toContain(
154 KEINE_SELBSTEINRICHTUNG,
155 );
156 });
157
158 it('nennt der Haken den Befehl, mit dem er eingerichtet wird', () => {
159 expect(HAKENTEXT).toContain('git config core.hooksPath .githooks');
160 });
161 });
162
163 describe('.githooks/pre-commit - die Grenze der Zusage', () => {
164 /*
165 * Der Kopf sagt zu, der Lauf fange ab, "was sich sonst erst beim Anwender
166 * zeigt". Das gilt fuer den Arbeitsbaum. Die vier Stufen von gate:schnell
167 * bekommen keinen Pfad und lesen keinen Bereitstellungsbereich - bei
168 * teilweiser Bereitstellung sagt der Lauf nichts ueber den Commit aus. Diese
169 * Grenze gehoert daneben, sonst ist die Zusage zu weit gefasst.
170 */
171 it('sagt, dass der Arbeitsbaum geprueft wird und nicht der bereitgestellte Stand', () => {
172 expect(HAKENTEXT, 'Grenze der Zusage').toContain(
173 'Geprueft wird dabei der Arbeitsbaum, nicht der bereitgestellte Stand',
174 );
175 });
176
177 it('nennt die Handgriffe, bei denen die Grenze greift', () => {
178 expect(HAKENTEXT, 'Hinweis auf teilweise Bereitstellung').toContain('git add -p');
179 expect(HAKENTEXT, 'Hinweis auf git commit mit Pfad').toContain('git commit <pfad>');
180 });
181 });