""" Tests für modules/basemap_stilvorlagen.py – lokale Stilvorlagen des Basemap-Layers (Basis #88). Gespeichert wird in einem temporären Ordner; der Layer schreibt statt einer echten QML-Datei eine kleine Textdatei. Laden und Speichern am echten Vektorkachel-Layer ist im QGIS-Test geprüft. """ import os import shutil import tempfile import unittest from sn_basis.modules.basemap_stilvorlagen import STANDARD_SCHLUESSEL, BasemapStilvorlagen class _Einstellungen: """Ersatz für QSettings – die Tests dürfen keine echten Benutzereinstellungen verändern.""" def __init__(self): self.daten = {} def value(self, k, standard=""): return self.daten.get(k, standard) def setValue(self, k, v): self.daten[k] = v def remove(self, k): self.daten.pop(k, None) class _Stil: def __init__(self, name): self._name = name def styleName(self): return self._name class _Layer: def __init__(self, stile=("Kontur_Kreisstr", "Decker_Kreisstr"), speichern_ok=True): self.stile = list(stile) self.geladen = None self.neu_gezeichnet = False self._speichern_ok = speichern_ok def name(self): return "Basemap.de - Farbe" def renderer(self): return type("R", (), {"styles": lambda s: [_Stil(n) for n in self.stile]})() def saveNamedStyle(self, pfad, kategorien): if not self._speichern_ok: return "kein Schreibrecht", False with open(pfad, "w", encoding="utf-8") as datei: datei.write("") return "", True def loadNamedStyle(self, pfad, kategorien): self.geladen = pfad return "", True def triggerRepaint(self): self.neu_gezeichnet = True class TestStilvorlagen(unittest.TestCase): def setUp(self): self.ordner = tempfile.mkdtemp() self.einstellungen = _Einstellungen() self.vorlagen = BasemapStilvorlagen(os.path.join(self.ordner, "stile"), self.einstellungen) def tearDown(self): shutil.rmtree(self.ordner, ignore_errors=True) def test_speichern_und_auflisten(self): """Prüft, dass eine gespeicherte Vorlage mit Anzeigenamen, QML-Datei und Begleitdatei aufgelistet wird.""" self.vorlagen.speichern(_Layer(), "Ohne Hausnummern", {"ausgeblendet": ["wald"], "eingeblendet": []}) liste = self.vorlagen.liste() self.assertEqual([v.anzeigename for v in liste], ["Ohne Hausnummern"]) self.assertEqual(liste[0].name, "Ohne_Hausnummern") self.assertTrue(os.path.exists(liste[0].pfad)) self.assertEqual(self.vorlagen.legendenauswahl("Ohne_Hausnummern")["ausgeblendet"], ["wald"]) def test_mehrere_varianten_alphabetisch(self): """Prüft, dass mehrere Varianten nebeneinander bestehen und alphabetisch nach Anzeigename sortiert werden.""" for name in ("Zeichnung", "Abstimmung", "mit Gebäuden"): self.vorlagen.speichern(_Layer(), name) self.assertEqual([v.anzeigename for v in self.vorlagen.liste()], ["Abstimmung", "mit Gebäuden", "Zeichnung"]) def test_leerer_name_oder_fehler_beim_schreiben(self): """Prüft, dass ein leerer Name und ein Schreibfehler von QGIS als ValueError gemeldet werden.""" with self.assertRaises(ValueError): self.vorlagen.speichern(_Layer(), " ") with self.assertRaises(ValueError): self.vorlagen.speichern(_Layer(speichern_ok=False), "Test") def test_laden_setzt_stil_und_zeichnet_neu(self): """Prüft, dass das Laden die QML-Datei der Vorlage in den Layer lädt und neu zeichnen lässt.""" self.vorlagen.speichern(_Layer(), "Standard LNO") layer = _Layer() self.vorlagen.laden(layer, "Standard_LNO") self.assertTrue(layer.geladen.endswith("Standard_LNO.qml")) self.assertTrue(layer.neu_gezeichnet) with self.assertRaises(ValueError): self.vorlagen.laden(layer, "gibt_es_nicht") def test_passung_meldet_fremde_styles(self): """Prüft, dass Style-Namen der Vorlage gemeldet werden, die der Ziel-Layer nicht kennt.""" self.vorlagen.speichern(_Layer(stile=("A", "B", "C")), "Grau") self.assertEqual(self.vorlagen.pruefe_passung(_Layer(stile=("A",)), "Grau"), ["B", "C"]) self.assertEqual(self.vorlagen.pruefe_passung(_Layer(stile=("A", "B", "C")), "Grau"), []) def test_standard_setzen_und_beim_loeschen_entfernen(self): """Prüft, dass eine Vorlage als Standard markiert wird und die Markierung beim Löschen der Vorlage entfällt.""" self.vorlagen.speichern(_Layer(), "Standard LNO") self.vorlagen.setze_standard("Standard_LNO") self.assertTrue(self.vorlagen.liste()[0].standard) self.vorlagen.loeschen("Standard_LNO") self.assertEqual(self.vorlagen.liste(), []) self.assertEqual(self.vorlagen.standard(), "") self.assertNotIn(STANDARD_SCHLUESSEL, self.einstellungen.daten) with self.assertRaises(ValueError): self.vorlagen.setze_standard("Standard_LNO") def test_fehlende_begleitdatei_wird_toleriert(self): """Prüft, dass eine QML-Datei ohne Begleitdatei mit ihrem Dateinamen aufgelistet wird.""" os.makedirs(self.vorlagen.ordner, exist_ok=True) with open(os.path.join(self.vorlagen.ordner, "Alt.qml"), "w", encoding="utf-8") as datei: datei.write("") self.assertEqual([v.anzeigename for v in self.vorlagen.liste()], ["Alt"]) self.assertIsNone(self.vorlagen.legendenauswahl("Alt")) self.assertEqual(self.vorlagen.pruefe_passung(_Layer(), "Alt"), []) def test_ohne_ordner_leere_liste(self): """Prüft, dass ohne angelegten Vorlagenordner eine leere Liste zurückkommt.""" self.assertEqual(self.vorlagen.liste(), []) if __name__ == "__main__": unittest.main()