578472872e
- [ocr].timeout wird als tesseract_timeout (pro Seite) an ocrmypdf durchgereicht; Default 1800 -> 300, 0 = ocrmypdf-Default - Exceptions nach dem OCR zaehlen als Fehler, Datei wird nach error/ gerettet - Fehlgeschlagene Uploads zaehlen als Fehler und loesen Fehler-Mail aus - name_mode wird im Preflight geprueft, nicht erst pro Datei - Fehlende [paths]-Sektion -> ConfigError mit klarer Meldung statt KeyError - Stabilitaets-Timeout zaehlt als Fehler (--once liefert Exit 1) - upload_folder nutzt shutil.copyfile statt read_bytes/write_bytes - OcrConfig.pdfa_level Default "2" -> "" (Ghostscript-Bug, Issue #3) - 35 neue Tests (92 gesamt), pytest.ini - AI_AGENT_BRIEFING.md auf Stand 0.4.0 gebracht Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
"""Tests für verständliche Fehlermeldungen beim Laden der Config."""
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from pdf_ocr_hotfolder.config import ConfigError, load_config
|
|
|
|
_FULL_PATHS = """
|
|
[paths]
|
|
incoming = "/tmp/in"
|
|
outgoing = "/tmp/out"
|
|
working = "/tmp/work"
|
|
error = "/tmp/err"
|
|
"""
|
|
|
|
|
|
def _write(tmp_path: Path, content: str) -> Path:
|
|
cfg = tmp_path / "config.toml"
|
|
cfg.write_text(content)
|
|
return cfg
|
|
|
|
|
|
def test_missing_paths_section(tmp_path: Path) -> None:
|
|
"""Fehlt [paths] komplett → ConfigError statt KeyError."""
|
|
cfg = _write(tmp_path, '[ocr]\nlanguages = "deu"\n')
|
|
with pytest.raises(ConfigError) as exc:
|
|
load_config(cfg)
|
|
msg = str(exc.value)
|
|
assert "[paths]" in msg
|
|
assert str(cfg) in msg
|
|
|
|
|
|
def test_empty_config_file(tmp_path: Path) -> None:
|
|
cfg = _write(tmp_path, "")
|
|
with pytest.raises(ConfigError, match=r"\[paths\]"):
|
|
load_config(cfg)
|
|
|
|
|
|
@pytest.mark.parametrize("missing", ["incoming", "outgoing", "working", "error"])
|
|
def test_missing_single_path_key(tmp_path: Path, missing: str) -> None:
|
|
"""Fehlt ein einzelner Key, wird genau dieser genannt."""
|
|
lines = [line for line in _FULL_PATHS.strip().splitlines()
|
|
if not line.startswith(missing)]
|
|
cfg = _write(tmp_path, "\n".join(lines) + "\n")
|
|
with pytest.raises(ConfigError) as exc:
|
|
load_config(cfg)
|
|
msg = str(exc.value)
|
|
assert missing in msg
|
|
assert str(cfg) in msg
|
|
|
|
|
|
def test_empty_path_value_is_rejected(tmp_path: Path) -> None:
|
|
"""Ein leerer Pfad ist genauso falsch wie ein fehlender."""
|
|
cfg = _write(tmp_path, _FULL_PATHS.replace('working = "/tmp/work"',
|
|
'working = ""'))
|
|
with pytest.raises(ConfigError, match="working"):
|
|
load_config(cfg)
|
|
|
|
|
|
def test_complete_paths_section_loads(tmp_path: Path) -> None:
|
|
cfg = _write(tmp_path, _FULL_PATHS)
|
|
loaded = load_config(cfg)
|
|
assert loaded.paths.incoming == Path("/tmp/in")
|
|
assert loaded.paths.error == Path("/tmp/err")
|
|
|
|
|
|
def test_main_returns_2_on_broken_config(tmp_path: Path, monkeypatch, capsys) -> None:
|
|
"""CLI bricht sauber mit Exit-Code 2 ab — ohne Traceback."""
|
|
cfg = _write(tmp_path, '[ocr]\nlanguages = "deu"\n')
|
|
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 "[paths]" in err
|