# -*- coding: utf-8 -*- """Tests für Bibliotheks-Erweiterung (Medikamente, Korrekturen, Doku-Prompt-Trennung).""" from __future__ import annotations import json import os import tempfile import unittest from unittest.mock import patch class TestBibliothekSystem(unittest.TestCase): def test_dafalgan_spelling_in_defaults(self): from aza_public_medication_terms import PUBLIC_CORRECTION_VARIANTS, build_public_medication_entries self.assertIn("Daffalgan", PUBLIC_CORRECTION_VARIANTS) self.assertEqual(PUBLIC_CORRECTION_VARIANTS["Daffalgan"], "Dafalgan") brands = {e["brand_name"] for e in build_public_medication_entries()} self.assertIn("Dafalgan", brands) self.assertNotIn("Daffalgan", brands) def test_daffalgan_to_dafalgan_apply(self): from aza_persistence import apply_korrekturen data = {"medikamente": {}, "begriffe": {}, "diagnosen": {}, "personen": {}, "_inactive": {}, "_metadata": {}} out, applied = apply_korrekturen("Patient nimmt Daffalgan.", data) self.assertIn("Dafalgan", out) self.assertNotIn("Daffalgan", out) self.assertTrue(any(a[1] == "Dafalgan" for a in applied)) def test_dafalgan_unchanged(self): from aza_persistence import apply_korrekturen data = {"medikamente": {}, "begriffe": {}, "diagnosen": {}, "personen": {}, "_inactive": {}, "_metadata": {}} out, _ = apply_korrekturen("Dafalgan 500 mg", data) self.assertIn("Dafalgan", out) def test_private_overrides_public(self): from aza_bibliothek import merge_public_korrekturen from aza_persistence import apply_korrekturen data = { "medikamente": {"Daffalgan": "MeinMedikament"}, "begriffe": {}, "diagnosen": {}, "personen": {}, "_inactive": {}, "_metadata": {}, } merged = merge_public_korrekturen(data) self.assertEqual(merged["medikamente"]["Daffalgan"], "MeinMedikament") out, applied = apply_korrekturen("Daffalgan", data) self.assertEqual(out, "MeinMedikament") self.assertEqual(applied[0][1], "MeinMedikament") def test_inactive_ignored(self): from aza_persistence import apply_korrekturen data = { "medikamente": {"Daffalgan": "Dafalgan"}, "begriffe": {}, "diagnosen": {}, "personen": {}, "_inactive": {"medikamente": ["Daffalgan"]}, "_metadata": {}, } out, applied = apply_korrekturen("Daffalgan", data) self.assertEqual(out, "Daffalgan") self.assertEqual(applied, []) def test_word_boundaries_no_partial(self): from aza_persistence import apply_korrekturen data = {"medikamente": {"Tremfia": "Tremfya"}, "begriffe": {}, "diagnosen": {}, "personen": {}, "_inactive": {}, "_metadata": {}} out, _ = apply_korrekturen("Tremfiatisch", data) self.assertEqual(out, "Tremfiatisch") out2, _ = apply_korrekturen("Tremfia", data) self.assertEqual(out2, "Tremfya") def test_longer_terms_first(self): from aza_persistence import apply_korrekturen data = { "medikamente": {"Trem": "X", "Tremfia": "Tremfya"}, "begriffe": {}, "diagnosen": {}, "personen": {}, "_inactive": {}, "_metadata": {}, } out, _ = apply_korrekturen("Tremfia", data) self.assertEqual(out, "Tremfya") def test_public_medications_available(self): from aza_bibliothek import list_public_entries meds = list_public_entries(category="medication") self.assertGreater(len(meds), 20) daf = next((m for m in meds if m.get("brand_name") == "Dafalgan"), None) self.assertIsNotNone(daf) self.assertEqual(daf.get("active_substance"), "Paracetamol") def test_adopt_public_correction(self): import aza_persistence as ap from aza_bibliothek import adopt_public_entry with tempfile.TemporaryDirectory() as td: path = os.path.join(td, "korrekturen.json") with patch.object(ap, "_korrekturen_config_path", return_value=path): entry = { "category": "medication", "term": "Fuzidin", "preferred_spelling": "Fucidin", "variants": ["Fuzidin"], "source": "AzA kuratiert", } ok, _ = adopt_public_entry(entry) self.assertTrue(ok) data = ap.load_korrekturen() self.assertEqual(data["medikamente"]["Fuzidin"], "Fucidin") def test_publish_payload_sanitize(self): from aza_bibliothek import publish_payload_sanitize ok, _ = publish_payload_sanitize({"term": "Dafalgan", "preferred_spelling": "Dafalgan"}) self.assertTrue(ok) bad, reason = publish_payload_sanitize({"patient_name": "Max"}) self.assertFalse(bad) self.assertIn("patient", reason.lower()) def test_sync_serialization(self): from aza_bibliothek import serialize_term_for_sync payload = serialize_term_for_sync({ "item_id": "x1", "category": "medication", "term": "Daffalgan", "preferred_spelling": "Dafalgan", "scope": "private", }) self.assertEqual(payload["item_type"], "library_term") self.assertEqual(payload["trigger"], "Daffalgan") self.assertEqual(payload["content"], "Dafalgan") def test_doku_prompts_separate_from_medications(self): from aza_bibliothek import list_public_entries meds = list_public_entries(category="medication") for m in meds: self.assertNotEqual(m.get("category"), "doku_prompt") def test_no_daffalgan_in_doku_defaults(self): from aza_doku_vorlagen import AZA_DEFAULT_TEMPLATES blob = json.dumps(AZA_DEFAULT_TEMPLATES) self.assertNotIn("Daffalgan", blob) self.assertIn("Dafalgan", blob) # ── Bibliothek-UI: Doku-Prompts entfernt, Kategorien/Buttons korrekt ──────── def test_categories_have_no_doku_prompt(self): from aza_bibliothek import PRIVATE_UI_CATEGORIES, PUBLIC_UI_CATEGORIES self.assertNotIn("doku_prompt", PRIVATE_UI_CATEGORIES) self.assertNotIn("doku_prompt", PUBLIC_UI_CATEGORIES) self.assertEqual( tuple(PRIVATE_UI_CATEGORIES), ("medication", "medical_term", "person", "correction"), ) self.assertEqual( tuple(PUBLIC_UI_CATEGORIES), ("medication", "medical_term", "correction"), ) def test_ui_module_markers(self): path = os.path.join(os.path.dirname(__file__), "aza_bibliothek_ui.py") with open(path, encoding="utf-8") as fh: src = fh.read() self.assertIn("Eigene Bibliothek", src) self.assertIn("Öffentliche Bibliothek", src) self.assertIn("_HDR_BG", src) self.assertNotIn("ttk.Combobox", src) # Doku-Prompts dürfen nicht mehr Teil der Bibliothek-UI sein self.assertNotIn("doku_prompt", src) self.assertNotIn("Doku-Prompt", src) # vereinfachte, verständliche Buttontexte self.assertIn("Neuer Eintrag", src) self.assertIn("Deaktivieren", src) self.assertIn("Aktivieren", src) self.assertIn("Übernehmen", src) def test_ui_window_size_set(self): import aza_bibliothek_ui as ui self.assertGreaterEqual(ui._WIN_W, 1200) self.assertGreaterEqual(ui._WIN_H, 800) self.assertGreaterEqual(ui._WIN_MIN_W, 1100) self.assertGreaterEqual(ui._WIN_MIN_H, 760) # ── Automatischer Dokumenttyp: Routing + Status (Root-Cause-Fix) ──────────── def test_status_label_kg(self): from aza_doku_vorlagen import doc_type_status_label self.assertEqual(doc_type_status_label("kg"), "Krankengeschichte") def test_status_label_verlauf(self): from aza_doku_vorlagen import doc_type_status_label self.assertEqual(doc_type_status_label("verlauf"), "Verlauf") self.assertNotEqual(doc_type_status_label("verlauf"), "Krankengeschichte") def test_status_labels_all_types(self): from aza_doku_vorlagen import doc_type_status_label self.assertEqual(doc_type_status_label("brief"), "Brief") self.assertEqual(doc_type_status_label("rezept"), "Rezept") self.assertEqual(doc_type_status_label("op_bericht"), "OP-Bericht") self.assertEqual(doc_type_status_label("kogu"), "KOGU") self.assertEqual(doc_type_status_label("arztzeugnis"), "Arztzeugnis") self.assertEqual(doc_type_status_label("eigenes_dokument"), "Eigenes Dokument") def test_route_kg_vs_verlauf(self): from aza_doku_vorlagen import resolve_doc_generation_route self.assertEqual(resolve_doc_generation_route("kg"), "kg") self.assertEqual(resolve_doc_generation_route("verlauf"), "generate") self.assertNotEqual(resolve_doc_generation_route("verlauf"), "kg") def test_route_all_types(self): from aza_doku_vorlagen import resolve_doc_generation_route self.assertEqual(resolve_doc_generation_route("brief"), "generate") self.assertEqual(resolve_doc_generation_route("rezept"), "generate") self.assertEqual(resolve_doc_generation_route("op_bericht"), "generate") self.assertEqual(resolve_doc_generation_route("kogu"), "generate") self.assertEqual(resolve_doc_generation_route("eigenes_dokument"), "generate") self.assertEqual(resolve_doc_generation_route("arztzeugnis"), "form") # Unbekannt fällt sicher auf KG zurück (kein stiller falscher Generator) self.assertEqual(resolve_doc_generation_route("unbekannt"), "kg") def test_auto_path_uses_doc_type(self): """Statischer Nachweis: der automatische Aufnahme-Pfad verwendet den gewählten Dokumenttyp und nicht hart 'kg'.""" path = os.path.join(os.path.dirname(__file__), "basis14.py") with open(path, encoding="utf-8") as fh: src = fh.read() self.assertIn("auto_doc_type = getattr(self, \"_current_doc_type\"", src) self.assertIn("self._next_phase(auto_doc_type)", src) self.assertIn("_auto_generate_doc_after_recording", src) self.assertIn("resolve_doc_generation_route", src) def test_no_kg_reset_in_basis(self): path = os.path.join(os.path.dirname(__file__), "basis14.py") with open(path, encoding="utf-8") as fh: src = fh.read() self.assertNotIn("_reset_doc_type_to_kg", src) def test_verlauf_status_not_kg_in_mixin(self): path = os.path.join(os.path.dirname(__file__), "aza_text_windows_mixin.py") with open(path, encoding="utf-8") as fh: src = fh.read() self.assertIn('self._start_timer("verlauf")', src) # ── Regression: "Unbekannte Kategorie: Verlauf" ──────────────────────────── def test_save_to_ablage_unknown_category_no_raise(self): import aza_persistence as ap # "Verlauf"/"OP-Berichte" sind keine Ablage-Ordner → darf NICHT werfen, # kein blockierender Dialog, Rückgabe None. self.assertIsNone(ap.save_to_ablage("Verlauf", "Testinhalt")) self.assertIsNone(ap.save_to_ablage("OP-Berichte", "Testinhalt")) def test_valid_ablage_categories_unchanged(self): from aza_config import ABLAGE_SUBFOLDERS for cat in ("KG", "Briefe", "Rezepte", "Kostengutsprachen", "Diktat", "Transkript"): self.assertIn(cat, ABLAGE_SUBFOLDERS) def test_mixin_no_invalid_save_categories(self): path = os.path.join(os.path.dirname(__file__), "aza_text_windows_mixin.py") with open(path, encoding="utf-8") as fh: src = fh.read() self.assertNotIn('save_category="Verlauf"', src) self.assertNotIn('cat="OP-Berichte"', src) def test_verlauf_generator_uses_chat_completion_like_kg(self): # Verlauf nutzt denselben Dokumentpfad wie KG (call_chat_completion → /v1/chat), # keinen separaten Chat-Sendepfad. path = os.path.join(os.path.dirname(__file__), "basis14.py") with open(path, encoding="utf-8") as fh: src = fh.read() self.assertIn("def summarize_verlauf_text", src) self.assertIn("def summarize_text", src) self.assertIn("self.call_chat_completion", src) def test_server_schema_function(self): import sqlite3 from aza_bibliothek_sync import ensure_published_library_terms_schema con = sqlite3.connect(":memory:") ensure_published_library_terms_schema(con) row = con.execute( "SELECT name FROM sqlite_master WHERE type='table' AND name='published_library_terms'" ).fetchone() self.assertIsNotNone(row) if __name__ == "__main__": unittest.main()