# -*- coding: utf-8 -*- """Tests fuer lib/parameter.py und cfg/parameter.ini.""" from __future__ import annotations import configparser import re from pathlib import Path import pytest import parameter from parameter import ParameterError, get_float, get_int ROOT = Path(__file__).resolve().parent.parent BASE = ROOT / "cfg" / parameter.PARAMETER_FILE @pytest.fixture def frisch(monkeypatch: pytest.MonkeyPatch): """Parameter-Cache leeren, damit SKEL_CFG im Test wirkt - und danach wieder.""" parameter._parser.cache_clear() yield monkeypatch parameter._parser.cache_clear() def _base() -> configparser.ConfigParser: parser = configparser.ConfigParser(inline_comment_prefixes=(";", "#")) parser.read(BASE, encoding="utf-8") return parser def test_base_values_are_read(frisch: pytest.MonkeyPatch) -> None: frisch.delenv("SKEL_CFG", raising=False) assert get_float("kreisel_junctions", "contact_tolerance") == 50.0 assert get_int("tro_flow", "min_store_lanes") == 2 def test_skel_cfg_overrides_single_value(frisch: pytest.MonkeyPatch, tmp_path: Path) -> None: (tmp_path / parameter.PARAMETER_FILE).write_text( "[kreisel_junctions]\ncontact_tolerance = 75 ; Anlage X\n", encoding="utf-8") frisch.setenv("SKEL_CFG", str(tmp_path)) assert get_float("kreisel_junctions", "contact_tolerance") == 75.0 # nicht ueberschriebene Werte kommen weiter aus der Grunddatei assert get_float("kreisel_junctions", "separator_tolerance") == 100.0 def test_missing_key_is_an_error(frisch: pytest.MonkeyPatch) -> None: frisch.delenv("SKEL_CFG", raising=False) with pytest.raises(ParameterError, match=r"\[tro_flow\] gibt_es_nicht fehlt"): get_float("tro_flow", "gibt_es_nicht") def test_non_number_is_an_error(frisch: pytest.MonkeyPatch, tmp_path: Path) -> None: (tmp_path / parameter.PARAMETER_FILE).write_text( "[tro_flow]\nmin_store_lanes = zwei\n", encoding="utf-8") frisch.setenv("SKEL_CFG", str(tmp_path)) with pytest.raises(ParameterError, match="keine ganze Zahl"): get_int("tro_flow", "min_store_lanes") def test_every_key_is_used_by_its_module() -> None: """Jeder Schluessel der Grunddatei wird in lib/.py gelesen - keine verwaisten Werte, die nichts mehr steuern.""" parser = _base() for section in parser.sections(): source = (ROOT / "lib" / f"{section}.py").read_text(encoding="utf-8") for key in parser.options(section): assert re.search(rf'"{key}"', source), f"[{section}] {key} wird nicht gelesen"