"""Tests für die KV-Varianten-Map (Odoo library_variant_id ↔ KB kv-kvt-IDs).""" import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] def load_map() -> dict: return json.loads( (ROOT / "tools" / "catalogs" / "kv_variant_map.json").read_text(encoding="utf-8") ) def load_kb_catalog() -> dict: return json.loads( (ROOT / "tools" / "catalogs" / "kv_catalog.json").read_text(encoding="utf-8") ) def test_map_structure_and_kb_id_integrity(): kb = load_kb_catalog() kb_ids = {e["id"] for e in kb["entries"].values()} variant_map = load_map() variants = variant_map["variants"] assert variants, "Mapping muss Varianten enthalten" referenced = set() for vid, variant in variants.items(): assert variant["variant_id"] == vid assert variant["docs"], f"leere Variante: {vid}" assert variant["confidence"] in ("matched", "low") for doc in variant["docs"]: assert {"kv_kvt_id", "slug", "doctype"} <= set(doc) referenced.add(doc["kv_kvt_id"]) assert referenced <= kb_ids, "Mapping darf nur existierende KB-IDs führen" # Unmatched-Einträge sind ebenfalls echte KB-IDs und decken den Rest ab unmatched = variant_map["unmatched_kb_entries"] assert set(unmatched) <= kb_ids stats = variant_map["stats"] assert stats["n_kb_entries_covered"] + stats["n_kb_entries_unmatched"] == ( stats["n_kb_entries_total"] ) assert stats["n_variants"] == len(variants) def test_odoo_seed_variants_are_covered(): """Odoo-Seed-KVs (kv_seed.xml): SI-2203 Handwerk und Gewerbe, SI-2748 Metallgewerbe müssen KV- und Tabellendokumente führen.""" variants = load_map()["variants"] seeds = {vid: variants.get(vid) for vid in ("SI-2203_de", "SI-2748_de")} assert seeds["SI-2203_de"] and seeds["SI-2203_de"]["confidence"] == "matched" assert seeds["SI-2748_de"] and seeds["SI-2748_de"]["confidence"] == "matched" slugs_2203 = {d["slug"] for d in seeds["SI-2203_de"]["docs"]} slugs_2748 = {d["slug"] for d in seeds["SI-2748_de"]["docs"]} assert "kollektivvertrag-gewerbe-handwerk-und-dienstleistung-2026" in slugs_2203 assert "gehaltsordnung-gewerbe-handwerk-dienstleistung-2026" in slugs_2203 assert "kollektivvertrag-abschluss-angestellte-metallgewerbe-2026" in slugs_2748 assert "lohnordnung-metallgewerbe-arbeiter-2026" in slugs_2748 def test_doc_pairs_keep_slug_and_id_correspondence(): kb = load_kb_catalog() by_id = {e["id"]: e for e in kb["entries"].values()} variant_map = load_map() checked = 0 for variant in variant_map["variants"].values(): for doc in variant["docs"]: entry = by_id[doc["kv_kvt_id"]] url_slug = entry["url"].rstrip("/").rsplit("/", 1)[-1] assert url_slug == doc["slug"], ( f"{doc['kv_kvt_id']}: {url_slug} != {doc['slug']}" ) checked += 1 assert checked >= 400