"""Punkt 5: Relative Pfade in der Config sind ein Fehler, keine stille Annahme. `incoming = "in"` legte das Verzeichnis unter dem WorkingDirectory des Dienstes an (/opt/pdf-ocr-hotfolder/in) statt dort, wo der Scanner ablegt — ohne Warnung. Der Dienst schaute dann dauerhaft ins Leere. """ from __future__ import annotations import sys from pathlib import Path import pytest from pdf_ocr_hotfolder.config import ConfigError, load_config _ABS = { "incoming": "/var/lib/pdf-ocr-hotfolder/incoming", "outgoing": "/var/lib/pdf-ocr-hotfolder/outgoing", "working": "/var/lib/pdf-ocr-hotfolder/working", "error": "/var/lib/pdf-ocr-hotfolder/error", } def _write(tmp_path: Path, paths: dict[str, str], extra: str = "") -> Path: cfg = tmp_path / "config.toml" zeilen = "\n".join(f'{k} = "{v}"' for k, v in paths.items()) cfg.write_text(f"[paths]\n{zeilen}\n{extra}") return cfg @pytest.mark.parametrize("key", list(_ABS)) def test_relative_path_key_is_rejected(tmp_path: Path, key: str) -> None: paths = dict(_ABS) paths[key] = "in" with pytest.raises(ConfigError) as exc: load_config(_write(tmp_path, paths)) msg = str(exc.value) assert key in msg assert "absolut" in msg.lower() assert "WorkingDirectory" in msg def test_dot_relative_path_is_rejected(tmp_path: Path) -> None: """Auch './scans' und '../scans' sind relativ.""" paths = dict(_ABS, incoming="./scans") with pytest.raises(ConfigError, match="incoming"): load_config(_write(tmp_path, paths)) def test_absolute_paths_load(tmp_path: Path) -> None: cfg = load_config(_write(tmp_path, _ABS)) assert cfg.paths.incoming == Path(_ABS["incoming"]) def test_relative_archive_dir_is_rejected(tmp_path: Path) -> None: cfg = _write(tmp_path, _ABS, '\n[output]\noriginal_on_success = "archive"\n' 'archive_dir = "archiv"\n') with pytest.raises(ConfigError) as exc: load_config(cfg) assert "archive_dir" in str(exc.value) def test_relative_upload_target_is_rejected(tmp_path: Path) -> None: cfg = _write(tmp_path, _ABS, '\n[upload.folder]\nenabled = true\ntarget = "fertig"\n') with pytest.raises(ConfigError) as exc: load_config(cfg) assert "target" in str(exc.value) def test_empty_archive_dir_and_target_are_fine(tmp_path: Path) -> None: """Leer heißt 'nicht gesetzt' und bleibt erlaubt (das ist der Default).""" cfg = load_config(_write(tmp_path, _ABS, '\n[output]\narchive_dir = ""\n' '\n[upload.folder]\ntarget = ""\n')) assert cfg.output.archive_dir == "" assert cfg.folder.target == "" def test_absolute_archive_dir_and_target_load(tmp_path: Path) -> None: cfg = load_config(_write(tmp_path, _ABS, '\n[output]\narchive_dir = "/srv/archiv"\n' '\n[upload.folder]\ntarget = "/srv/fertig"\n')) assert cfg.output.archive_dir == "/srv/archiv" assert cfg.folder.target == "/srv/fertig" # ---------------- CLI ---------------- def test_main_returns_2_on_relative_path(tmp_path: Path, monkeypatch, capsys) -> None: cfg = _write(tmp_path, dict(_ABS, incoming="in")) monkeypatch.setattr(sys, "argv", ["pdf-ocr-hotfolder", "--config", str(cfg), "--once"]) from pdf_ocr_hotfolder.__main__ import main assert main() == 2 err = capsys.readouterr().err assert "FEHLER" in err assert "incoming" in err def test_check_config_returns_2_on_relative_path(tmp_path: Path, monkeypatch, capsys) -> None: from pdf_ocr_hotfolder.__main__ import CHECK_ERROR, main cfg = _write(tmp_path, dict(_ABS, outgoing="raus")) monkeypatch.setattr(sys, "argv", ["pdf-ocr-hotfolder", "--config", str(cfg), "--check-config"]) assert main() == CHECK_ERROR assert "outgoing" in capsys.readouterr().err