"""Tests für tools/ingest_sources.py: KV-HTML-Konverter, RIS-Intake, LAW_MAP."""
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from tools import ingest_sources as ing # noqa: E402
from tools.kb_common import LAW_MAP # noqa: E402
WKO_HTML = """
Lohnabkommen für Testgewerbe
Inhalt
§ 1 Geltungsbereich
§ 1 Geltungsbereich
Für alle Betriebe
des Testgewerbes.
§ 2 Mindestlöhne
| Gruppe | Betrag |
| A1 | € 2.020,00 |
| B1 | C1 | € 2.100,00 |
Text nach Tabelle.
"""
@pytest.fixture()
def converted():
soup = ing.prep_soup(WKO_HTML)
main = soup.find("main", class_="col-lg-8")
meta = ing.parse_kv_meta(main)
return meta, ing.blocks_to_md(main)
def test_kv_meta_and_geltungsdauer(converted):
meta, _ = converted
assert meta == [
("Räumlicher Geltungsbereich", "Österreichweit"),
("Geltungsdauer", "ab 1.4.2026"),
]
title = "Lohnordnung Testgewerbe, gültig ab 1.4.2026"
stand, tags = ing.derive_stand(title, meta, "test.html")
assert stand == "2026-04" and tags == []
def test_kv_stand_fallbacks():
stand, tags = ing.derive_stand("Lohnordnung X 2025", [], "x.html")
assert (stand, tags) == ("2025-01", ["stand-jahr"])
stand, tags = ing.derive_stand("Generalkollektivvertrag", [], "undatiert.html")
assert (stand, tags) == (ing.CRAWL_STAND, ["stand-geschaetzt"])
stand, _ = ing.derive_stand("KV X", [], "lohnordnung-x-2023.html")
assert stand == "2023-01"
def test_kv_blocks_heading_toc_table(converted):
_, lines = converted
md = "\n".join(lines)
assert "## Lohnabkommen für Testgewerbe" in md
assert "## § 1 Geltungsbereich" in md
assert "Für alle Betriebe\ndes Testgewerbes." in md
# TOC übersprungen
assert "§ 1 Geltungsbereich" not in md
assert "Content start" not in md
# Tabelle als Markdown, Pipe escaped
assert "| Gruppe | Betrag |" in md
assert "| --- | --- |" in md
assert "| A1 | € 2.020,00 |" in md
assert "| B1 \\| C1 | € 2.100,00 |" in md
assert "Text nach Tabelle." in md
def test_kv_entry_writes_frontmatter(tmp_path, monkeypatch):
catalog = {"source": "kv", "updated": None, "next_seq": 1, "entries": {}}
stats = {"kv_written": 0, "no_og": [], "no_main": []}
p = tmp_path / "lohnordnung-testgewerbe-2026.html"
p.write_text(WKO_HTML, encoding="utf-8")
slug, md = ing.kv_entry(p, catalog, stats)
assert slug.startswith("kv_")
assert "id: kv-kvt-001" in md
assert "topic: kollektivvertraege" in md
assert "stand: 2026-04" in md
assert "chapter: \"Lohnordnung\"" in md
assert "jahr-2026" in md
assert catalog["next_seq"] == 2
def test_doctype_classification():
assert ing.classify_doctype("Zusatz-KV Wachorgane 2026") == "Zusatz-KV"
assert ing.classify_doctype("Rahmenkollektivvertrag Textil 2026") == "Rahmen-KV"
assert ing.classify_doctype("Gehaltsordnung Information und Consulting") == "Gehaltsordnung"
assert ing.classify_doctype("Lohnordnung Friseur/in") == "Lohnordnung"
assert ing.classify_doctype("Empfehlung Lohntafeln Handel") == "Empfehlung"
assert ing.classify_doctype("Fragen und Antworten KV IT 2026") == "Fragen & Antworten"
assert ing.classify_doctype("Kollektivvertrag Handel Angestellte 2026") == "Kollektivvertrag"
assert ing.classify_doctype("Dienst- und Besoldungsordnung Privatbahnen") == "Dienst- und Besoldungsordnung"
def test_law_map_covers_all_ris_files():
ris_files = {p.stem for p in ing.RIS_DIR.glob("*.md")}
assert ris_files == set(LAW_MAP.keys()), "LAW_MAP und .ris/*.md müssen 1:1 passen"
def test_ris_entry(tmp_path, monkeypatch):
catalog = {"source": "ris", "updated": None, "next_seq": 1, "entries": {}}
stats = {"ris_written": 0, "ris_unmapped": []}
p = tmp_path / "TestG.md"
p.write_text(
"# Testgesetz (TestG)\n\n"
"Quelle: RIS (https://www.ris.bka.gv.at/), Gesetzesnummer 12345678, "
"Stand: 2026-09-13. Es sind nur die zitierten Paragraphen enthalten.\n\n"
"## § 1. Geltungsbereich\n\n(1) Dieses Gesetz gilt für alle.\n\n"
"## § 2. Anspruch\n\nEs besteht ein Anspruch.\n",
encoding="utf-8",
)
# LAW_MAP hat kein TestG — Mapping über Monkeypatch injizieren
monkeypatch.setitem(ing.LAW_MAP, "TestG", ("normen-sonstige", "Testrecht", 6))
slug, md = ing.ris_entry(p, catalog, stats)
assert slug == "ris_testg"
assert "id: ris-nso-06" in md
assert "stand: 2026-09" in md
assert 'legal_bases: ["TestG"]' in md
assert "## § 1. Geltungsbereich" in md
assert "(1) Dieses Gesetz gilt für alle." in md
assert "ris-nso-06" in md # ID-Zeile im Body