Files
aza/AzA march 2026/_test_bibliothek_system.py

282 lines
13 KiB
Python
Raw Normal View History

2026-06-10 22:55:03 +02:00
# -*- 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()