"""Audit-Report-Assembler (pur) — Sektionen, Cookie-Titel-Fix, Top-N-Deckelung, Severity-Statistik, Co-Pilot-Tonalität, kein Normtext.""" from compliance.services.audit_report import assemble_report, render_markdown META = {"snapshot_id": "abc-123", "site_label": "BMW", "site_domain": "bmw.de", "created_at": "2026-06-11T14:15:00", "check_id": "508983ec"} MODULES = { "cookie": {"findings": [ # Cookie-Befunde OHNE title-Feld (nur cookie/type/remediation) → Titel-Fix. {"cookie": "cto_bmw", "vendor": "Criteo", "type": "tracker_as_necessary", "severity": "HIGH", "remediation": "Als einwilligungspflichtig einstufen."}, {"cookie": "_ga", "vendor": "Google", "type": "excessive_lifetime", "severity": "LOW", "remediation": "Laufzeit reduzieren."}, {"cookie": "x1", "type": "missing_purpose", "severity": "MEDIUM"}, {"cookie": "x2", "type": "missing_purpose", "severity": "MEDIUM"}, {"cookie": "x3", "type": "missing_purpose", "severity": "MEDIUM"}, ]}, "impressum": {"findings": [ {"title": "Vertretungsberechtigte fehlen", "severity": "MEDIUM", "status": "fail", "recommendation": "Vertretungsberechtigte ergänzen."}, ], "mc_coverage": [1, 2, 3, 4]}, "browser": {"browser_matrix": {"browser_matrix": [ {"label": "Chromium", "score": 47, "summary": {"reject_respected": False, "violations": {"before_consent": 1}}}, ]}, "cross_findings": [ {"title": "Tracking vor der Einwilligung — in allen Browsern", "severity": "HIGH", "measure": "Tracking erst nach Consent laden."}, ]}, } def test_sections_present_incl_exec_and_gesamt(): titles = [s["title"] for s in assemble_report(META, MODULES)["sections"]] for t in ["Executive Summary", "Einleitung", "Testumfang & Methodik", "Detailbefunde", "Browser-Übersicht", "Gesamtanalyse", "Empfohlene Maßnahmen", "Rechtlicher Hinweis"]: assert t in titles, f"Sektion fehlt: {t}" def test_cookie_title_not_befund_fallback(): md = render_markdown(assemble_report(META, MODULES)) # Positiv: Cookie-Titel korrekt gebaut (Fallback "Befund" käme OHNE cto_bmw). assert "cto_bmw" in md and "Criteo" in md assert "Als notwendig deklariert" in md # Typ-Label statt roher type assert "**[Hoch]** Befund" not in md # kein nackter Fallback-Titel def test_top_n_cap_and_more_hint(): # cookie hat 5 Befunde → nur Top-3 + Verweis auf „weitere". md = render_markdown(assemble_report(META, MODULES)) assert "weitere Befund(e)" in md assert "abc-123" in md # Frontend-Link mit snapshot_id def test_severity_counts_and_bar(): r = assemble_report(META, MODULES) c = r["totals"]["by_severity"] assert c["HIGH"] == 2 and c["MEDIUM"] == 4 and c["LOW"] == 1 md = render_markdown(r) assert "▇" in md # Severity-Balken (Graphik) assert "Anforderungen (MCs) geprüft" in md # Modul-Statistik (Impressum mc_coverage) def test_copilot_disclaimer_and_no_normtext(): md = render_markdown(assemble_report(META, MODULES)) assert "DSB" in md and "Anwalt" in md and "Wahrscheinlichkeit" in md assert "§ 25 Abs. 2" in md and "nicht-essentielle" in md.lower() assert "BreakPilot" in md and "Browser-Übersicht" in md def test_empty_modules_graceful(): r = assemble_report({"site_domain": "example.com"}, {}) assert r["totals"]["findings"] == 0 md = render_markdown(r) assert "keine wesentlichen auffälligkeiten" in md.lower() assert "Rechtlicher Hinweis" in md