282 lines
13 KiB
Python
282 lines
13 KiB
Python
# -*- 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()
|