lsa-planer

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

/ tests services kartendienste.test.ts

4,7 KB Rohdatei
tests/services/kartendienste.test.ts — 118 Zeilen
1 import { describe, expect, it } from 'vitest';
2 import { erlaubteRechner, istErlaubt } from '../../electron/karte';
3 import {
4 KARTENDIENSTE,
5 baueKachelplan,
6 dienstMit,
7 herkunftstext,
8 rechnernamen,
9 } from '@/services/kartendienste';
10
11 /**
12 * Kartendienste.
13 *
14 * Zwei Dinge muessen hier stimmen, und beide waeren im Betrieb nur schwer zu
15 * bemerken:
16 *
17 * 1. Die Freigabeliste des Hauptprozesses muss alle eingetragenen Dienste
18 * enthalten. Fehlt einer, laesst sich der Dienst zwar auswaehlen, der Abruf
19 * scheitert aber mit einer Meldung, die wie ein Netzfehler aussieht.
20 *
21 * 2. Die Adressen, die das Programm tatsaechlich baut, muessen zu dieser Liste
22 * passen. Eine Adresse, die der Hauptprozess abweist, sieht fuer den
23 * Anwender wie ein Netzfehler aus.
24 *
25 * Der Zuschnitt des Ausschnitts steht in kachelplan.test.ts - dort wird gegen
26 * ausschnittUm() geprueft, also gegen Mittelpunkt UND Kantenlaenge.
27 */
28
29 const KNOTEN = { breite: 50.9412784, laenge: 6.9582814 };
30
31 describe('Freigabeliste', () => {
32 it('enthaelt jeden eingetragenen Kartendienst', () => {
33 const freigegeben = erlaubteRechner();
34 for (const name of rechnernamen()) {
35 expect(freigegeben, `Rechner ${name} fehlt in electron/karte.ts`).toContain(name);
36 }
37 });
38
39 it('laesst jede erzeugte Abrufadresse zu - auch jede einzelne Kachel', () => {
40 // Geprueft wird der Weg, den das Programm wirklich geht: Der Luftbilddialog
41 // ruft ausschliesslich baueKachelplan. Eine Kantenlaenge, die aufteilt,
42 // damit nicht nur die erste Adresse geprueft wird.
43 for (const dienst of KARTENDIENSTE) {
44 const plan = baueKachelplan({ dienst, mitte: KNOTEN, kantenlaenge: 600 });
45 expect(plan.kacheln.length, `${dienst.id} ohne Kacheln`).toBeGreaterThan(0);
46 for (const kachel of plan.kacheln) {
47 expect(
48 istErlaubt(kachel.url),
49 `${dienst.id}, Kachel ${kachel.spalte}/${kachel.zeile} nicht freigegeben`,
50 ).toBe(true);
51 }
52 }
53 });
54
55 it('weist fremde Rechner, unverschluesselte Verbindungen und Unsinn ab', () => {
56 expect(istErlaubt('https://beispiel.example/wms?REQUEST=GetMap')).toBe(false);
57 expect(istErlaubt('http://www.wms.nrw.de/geobasis/wms_nw_dop')).toBe(false);
58 expect(istErlaubt('file:///C:/Windows/win.ini')).toBe(false);
59 expect(istErlaubt('')).toBe(false);
60 // Der Rechnername steht am Ende der Autoritaet, nicht irgendwo darin.
61 expect(istErlaubt('https://www.wms.nrw.de.angreifer.example/x')).toBe(false);
62 expect(istErlaubt('https://angreifer.example/?x=www.wms.nrw.de')).toBe(false);
63 });
64 });
65
66 describe('Bildanforderung', () => {
67 /*
68 * Bildgroesse, Achsfolge, Massstab und Zuschnitt stehen in
69 * kachelplan.test.ts - dort am Weg, den das Programm geht. Hier bleibt, was
70 * dort fehlt: die Wahl der UTM-Zone. Der Kachelplan-Test prueft nur Zone 32,
71 * weil alle seine Kacheln in derselben Zone liegen muessen.
72 */
73 const dienst = dienstMit('nw-dop');
74
75 it('waehlt die UTM-Zone nach der geografischen Laenge', () => {
76 // Aachen liegt in Zone 32, Goerlitz in Zone 33. Die falsche Zone
77 // verschiebt den Ausschnitt um Hunderte Kilometer - der Dienst liefert
78 // dann ein leeres Bild.
79 const zoneVon = (laenge: number, breite: number): string | null => {
80 const plan = baueKachelplan({ dienst, mitte: { breite, laenge }, kantenlaenge: 200 });
81 return new URL(plan.kacheln[0]!.url).searchParams.get('CRS');
82 };
83 expect(zoneVon(6.0839, 50.7753)).toBe('EPSG:25832');
84 expect(zoneVon(14.9873, 51.1524)).toBe('EPSG:25833');
85 });
86 });
87
88 describe('Quellenangabe', () => {
89 it('nennt Herausgeber, Mittelpunkt und Kantenlaenge', () => {
90 const text = herkunftstext(dienstMit('nw-dop'), KNOTEN, 200);
91 expect(text).toContain('Geobasis NRW');
92 expect(text).toContain('50.941278');
93 // Sechs Nachkommastellen sind rund elf Zentimeter - genauer muss ein
94 // Ausschnittsmittelpunkt nicht sein. Die letzte Stelle haengt an der
95 // Binaerdarstellung, deshalb wird sie hier nicht mitgeprueft.
96 expect(text).toContain('6.95828');
97 expect(text).toContain('200 m');
98 });
99
100 it('fuehrt den vorgeschriebenen Vermerk mit, wo einer verlangt ist', () => {
101 for (const dienst of KARTENDIENSTE) {
102 if (dienst.namensnennung === null) continue;
103 expect(herkunftstext(dienst, KNOTEN, 200)).toContain(dienst.namensnennung);
104 }
105 });
106 });
107
108 describe('Eintraege', () => {
109 it('haben eindeutige Kennungen und https-Adressen', () => {
110 const kennungen = KARTENDIENSTE.map((d) => d.id);
111 expect(new Set(kennungen).size).toBe(kennungen.length);
112 for (const dienst of KARTENDIENSTE) {
113 expect(dienst.basisUrl.startsWith('https://'), dienst.id).toBe(true);
114 expect(dienst.aufloesung).toBeGreaterThan(0);
115 expect(dienst.nutzungsrecht.length).toBeGreaterThan(10);
116 }
117 });
118 });