# -*- coding: utf-8 -*- """Automatisierte Tests für Doku-Prompt-System.""" from __future__ import annotations import json import os import tempfile import unittest from unittest.mock import patch class TestDokuPromptSystem(unittest.TestCase): def setUp(self): self._tmpdir = tempfile.mkdtemp() self._orig_path_fn = None def tearDown(self): import shutil shutil.rmtree(self._tmpdir, ignore_errors=True) def _patch_templates_path(self): import aza_doku_vorlagen as dv path = os.path.join(self._tmpdir, "aza_document_templates.json") dv._templates_json_path = lambda: path # type: ignore return path, dv def test_doc_types_order(self): from aza_doku_vorlagen import DOC_TYPES labels = [l for _, l in DOC_TYPES] self.assertEqual(labels[0], "Krankengeschichte") self.assertEqual(labels[1], "Verlauf") self.assertEqual(labels[-1], "Eigenes Dokument") self.assertEqual(len(DOC_TYPES), 8) def test_verlauf_default_present(self): from aza_doku_vorlagen import AZA_DEFAULT_TEMPLATES, VERLAUF_DEFAULT_PROMPT self.assertIn("verlauf", AZA_DEFAULT_TEMPLATES) self.assertIn("Verlaufsbericht", VERLAUF_DEFAULT_PROMPT) def test_migration_v1_to_v2(self): path, dv = self._patch_templates_path() old = { "schema_version": 1, "active": {"kg": "aza_default", "brief": "aza_default"}, "templates": { "kg": [{"id": "aza_default", "name": "AzA-Grundvorlage", "is_system": True, "content": "KG alt", "created_at": "t", "updated_at": "t"}], "brief": [{"id": "aza_default", "name": "AzA-Grundvorlage", "is_system": True, "content": "Brief alt", "created_at": "t", "updated_at": "t"}], }, } with open(path, "w", encoding="utf-8") as f: json.dump(old, f) data = dv._load() self.assertEqual(data["schema_version"], 2) self.assertEqual(data["templates"]["kg"][0]["content"], "KG alt") self.assertIn("verlauf", data["templates"]) self.assertIn("eigenes_dokument", data["templates"]) def test_sanitize_strips_script(self): from aza_doku_vorlagen import sanitize_prompt_text s = sanitize_prompt_text("Verlauf") self.assertNotIn("script", s.lower()) self.assertIn("Verlauf", s) def test_dynamic_button_labels(self): from aza_doku_vorlagen import DOC_TYPE_CREATE_LABELS, DOC_TYPE_COPY_LABELS self.assertEqual(DOC_TYPE_CREATE_LABELS["verlauf"], "Verlauf erstellen") self.assertEqual(DOC_TYPE_COPY_LABELS["brief"], "Brief kopieren") def test_get_active_no_override_for_default(self): path, dv = self._patch_templates_path() dv._save(dv._default_structure()) from aza_text_windows_mixin import _get_doku_vorlage_for self.assertEqual(_get_doku_vorlage_for("kg"), "") self.assertEqual(_get_doku_vorlage_for("verlauf"), "") def test_get_active_user_template(self): path, dv = self._patch_templates_path() data = dv._default_structure() data["templates"]["verlauf"].append({ "id": "user_test", "name": "Mein Verlauf", "is_system": False, "content": "Custom Verlauf", "created_at": "t", "updated_at": "t", "revision": 1, }) data["active"]["verlauf"] = "user_test" dv._save(data) from aza_text_windows_mixin import _get_doku_vorlage_for self.assertEqual(_get_doku_vorlage_for("verlauf"), "Custom Verlauf") def test_copy_public_template(self): path, dv = self._patch_templates_path() dv._save(dv._default_structure()) new_id = dv.copy_public_template_as_own( "brief", content="Pub", title="Pub Brief", source_author="Dr. X", source_server_id="s1", ) self.assertTrue(new_id) data = dv._load() tpl = next(t for t in data["templates"]["brief"] if t["id"] == new_id) self.assertEqual(tpl["content"], "Pub") self.assertEqual(tpl["source_author"], "Dr. X") def test_atomic_save(self): path, dv = self._patch_templates_path() dv._save(dv._default_structure()) self.assertTrue(os.path.isfile(path)) self.assertFalse(os.path.isfile(path + ".tmp")) def test_merge_sync_newest_revision(self): from aza_doku_prompt_sync import merge_server_doku_items_local data = { "schema_version": 2, "active": {"kg": "aza_default"}, "templates": {"kg": []}, "sync_meta": {"conflicts": []}, } server_items = [{ "id": "user_1_kg", "item_type": "doku_prompt", "trigger": "kg", "content": json.dumps({ "doc_type": "kg", "name": "Sync KG", "content": "Synced", "revision": 2, "updated_at": "2026-01-02T00:00:00+00:00", }), }] data, changed = merge_server_doku_items_local(data, server_items) self.assertTrue(changed) self.assertEqual(data["templates"]["kg"][0]["content"], "Synced") def test_sync_serialization_private_only(self): from aza_doku_prompt_sync import local_private_templates_to_sync_items path, dv = self._patch_templates_path() data = dv._default_structure() data["templates"]["verlauf"].append({ "id": "user_v1", "name": "Privat", "is_system": False, "content": "Verlauf privat", "created_at": "t", "updated_at": "t", "revision": 3, }) dv._save(data) items = local_private_templates_to_sync_items(dv._load()) self.assertEqual(len(items), 1) self.assertEqual(items[0]["item_type"], "doku_prompt") self.assertEqual(items[0]["trigger"], "verlauf") payload = json.loads(items[0]["content"]) self.assertEqual(payload["content"], "Verlauf privat") self.assertEqual(payload["revision"], 3) def test_merge_conflict_keeps_local_when_newer(self): from aza_doku_prompt_sync import merge_server_doku_items_local data = { "schema_version": 2, "active": {"kg": "user_1_kg"}, "templates": {"kg": [{ "id": "user_1_kg", "name": "Lokal", "is_system": False, "content": "Lokal neu", "revision": 5, "updated_at": "2026-06-10T12:00:00+00:00", "created_at": "t", }]}, "sync_meta": {"conflicts": []}, } server_items = [{ "id": "user_1_kg", "item_type": "doku_prompt", "trigger": "kg", "content": json.dumps({ "doc_type": "kg", "name": "Server alt", "content": "Server alt", "revision": 2, "updated_at": "2026-01-01T00:00:00+00:00", }), }] merged, changed = merge_server_doku_items_local(data, server_items) self.assertEqual(merged["templates"]["kg"][0]["content"], "Lokal neu") self.assertTrue(len(merged["sync_meta"]["conflicts"]) >= 1) def test_publish_payload_fields(self): from aza_doku_prompt_sync import PublishDokuPromptIn p = PublishDokuPromptIn( doc_type="verlauf", title="Test", content="Prompt ohne Patientendaten", description="Demo", author_display="Dr. Test", ) self.assertEqual(p.doc_type, "verlauf") d = p.model_dump() self.assertNotIn("patient_name", d) self.assertNotIn("transcript", d) def test_load_all_templates_alias(self): path, dv = self._patch_templates_path() dv._save(dv._default_structure()) self.assertEqual(dv._load_all_templates()["schema_version"], 2) def test_active_per_doc_type(self): path, dv = self._patch_templates_path() data = dv._default_structure() for dt, _ in dv.DOC_TYPES: self.assertIn(dt, data["active"]) self.assertIn(dt, data["templates"]) def test_no_patient_fields_in_template_schema(self): path, dv = self._patch_templates_path() data = dv._default_structure() blob = json.dumps(data).lower() for forbidden in ("patient_name", "transcript", "geburtsdatum", "sozialversicherung"): self.assertNotIn(forbidden, blob) def test_office_shell_kg_section_markers(self): path = os.path.join(os.path.dirname(__file__), "aza_office_shell_v1.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn('"Doku-Prompt"', src) self.assertIn("DocTypePicker", src) self.assertIn("app._doc_type_picker", src) self.assertNotIn("app._doc_type_combo", src) self.assertNotIn('("Doku-Prompt", "_open_doku_vorlage_fenster")', src) self.assertNotIn('actions, "Kommentare"', src) self.assertIn('"autotext"', src) self.assertIn('"folder"', src) self.assertIn('"library"', src) def test_short_doc_type_labels(self): from aza_doku_vorlagen import ( DOC_TYPE_CREATE_LABELS_SHORT, DOC_TYPE_COPY_LABELS_SHORT, DOC_TYPE_KEYS, ) # Für jeden Dokumenttyp existiert ein Kurzlabel. for key in DOC_TYPE_KEYS: self.assertIn(key, DOC_TYPE_CREATE_LABELS_SHORT) self.assertIn(key, DOC_TYPE_COPY_LABELS_SHORT) self.assertEqual(DOC_TYPE_CREATE_LABELS_SHORT["verlauf"], "Verl. erst.") self.assertEqual(DOC_TYPE_COPY_LABELS_SHORT["verlauf"], "Verl. kop.") self.assertEqual(DOC_TYPE_CREATE_LABELS_SHORT["kg"], "KG erstellen") self.assertEqual(DOC_TYPE_CREATE_LABELS_SHORT["eigenes_dokument"], "Eig. Dok. erst.") # Kurzlabels sind nicht länger als die Langform. from aza_doku_vorlagen import DOC_TYPE_CREATE_LABELS self.assertLessEqual( len(DOC_TYPE_CREATE_LABELS_SHORT["verlauf"]), len(DOC_TYPE_CREATE_LABELS["verlauf"]), ) def test_office_shell_uses_short_labels(self): path = os.path.join(os.path.dirname(__file__), "aza_office_shell_v1.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn("DOC_TYPE_CREATE_LABELS_SHORT", src) self.assertIn("DOC_TYPE_COPY_LABELS_SHORT", src) def test_doku_window_button_texts(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn('"Veröffentlichen"', src) self.assertNotIn('"Für Ärzte veröffentlichen"', src) self.assertIn('"Öffentliche Vorlagen"', src) self.assertIn("btn_public_left", src) self.assertIn("open_public_doku_vorlagen_window", src) self.assertNotIn("Öffentliche Prompt-Bibliothek", src) self.assertNotIn('text="Als eigene Vorlage\\nübernehmen"', src) self.assertNotIn('text="Aktualisieren"', src) def test_publish_dialog_replaces_simpledialog(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn("def open_doku_publish_dialog", src) self.assertIn("dlg.title(window_title)", src) self.assertIn('window_title: str = "Vorlage veröffentlichen"', src) self.assertIn("⏺ Diktieren", src) self.assertIn("open_doku_publish_dialog(", src) publish_block = src.split("def _do_publish", 1)[-1].split("\n def ", 1)[0] self.assertNotIn("simpledialog.askstring", publish_block) self.assertNotIn("messagebox.askyesno", publish_block) def test_public_vorlagen_window_buttons(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() pub_block = src.split("def open_public_doku_vorlagen_window", 1)[-1].split("\ndef ", 1)[0] self.assertIn("In eigene Vorlage übernehmen", pub_block) self.assertIn("Bearbeiten", pub_block) self.assertIn("Löschen", pub_block) self.assertIn("Schliessen", pub_block) self.assertIn("create_tool_action_button", pub_block) self.assertIn("set_tool_action_button_enabled", pub_block) self.assertIn("action_bar.pack(side=\"bottom\"", pub_block) self.assertIn("load_local_prepared_public_items", pub_block) self.assertIn("detail_prompt", pub_block) self.assertIn("Eigene Veröffentlichung", pub_block) def test_tool_action_button_disabled_readable(self): from aza_ui_helpers import ( TOOL_ACTION_BTN_STYLES, create_tool_action_button, set_tool_action_button_enabled, ) for kind in ("primary", "secondary", "danger"): dis = TOOL_ACTION_BTN_STYLES[kind]["disabled"] fg = dis["fg"].upper() self.assertNotIn(fg, ("#FFFFFF", "#FFF")) self.assertIn("disabledforeground", dis) import tkinter as tk root = tk.Tk() root.withdraw() try: btn = create_tool_action_button(root, "Löschen", lambda: None, kind="danger") set_tool_action_button_enabled(btn, False) self.assertEqual(str(btn.cget("state")), "disabled") self.assertNotEqual(str(btn.cget("disabledforeground")).upper(), "#FFFFFF") finally: root.destroy() def test_load_local_prepared_public_items_helper(self): import tempfile import aza_doku_vorlagen as dv import aza_config with tempfile.TemporaryDirectory() as td: qpath = os.path.join(td, "doku_prompt_publish_queue.json") with open(qpath, "w", encoding="utf-8") as fh: json.dump([{ "document_type_key": "verlauf", "title": "Test", "description": "Beschreibung", "prompt_text": "Inhalt", "author_display_name": "Dr. X", }], fh) with patch.object(aza_config, "get_writable_data_dir", return_value=td): items = dv.load_local_prepared_public_items() self.assertEqual(len(items), 1) self.assertEqual(items[0]["doc_type"], "verlauf") self.assertEqual(items[0]["title"], "Test") def test_doku_window_larger(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn("_DOKU_WIN_W, _DOKU_WIN_H = 1080, 820", src) self.assertIn("_DOKU_WIN_MIN_W, _DOKU_WIN_MIN_H = 980, 700", src) self.assertIn("_PUBLIC_WIN_W, _PUBLIC_WIN_H = 1180, 860", src) self.assertIn("_PUBLISH_DLG_W, _PUBLISH_DLG_H = 720, 860", src) def test_public_vorlagen_window_structure(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn('win.title("Öffentliche Vorlagen")', src) self.assertIn("_PUBLIC_LIB_PLACEHOLDER", src) self.assertIn("Live-Bibliothek", src) def test_publish_user_message_text(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn("_PUBLISH_ROUTE_MSG", src) done_block = src.split("def _publish_done", 1)[-1] self.assertIn("_PUBLISH_ROUTE_MSG", done_block) def test_publish_route_missing_translation(self): # publish_doku_prompt liefert __ROUTE_MISSING__ bei fehlender Route (404), # damit die UI kein rohes "Not Found" zeigt. import aza_doku_prompt_sync as sync class _FakeApp: _user_profile = {"display_name": "Dr. Test"} def get_backend_url(self): return "https://example.invalid" def _empfang_self_user_id(self): return "u1" with patch.object(sync, "_sync_headers", return_value={"X-Api-Key": "x"}), \ patch.object(sync, "_http_post", return_value=(404, {"detail": "Not Found"})): ok, msg = sync.publish_doku_prompt(_FakeApp(), "verlauf", {"content": "x"}, "Titel") self.assertFalse(ok) self.assertEqual(msg, "__ROUTE_MISSING__") def test_publish_conn_error_translation(self): import aza_doku_prompt_sync as sync class _FakeApp: _user_profile = {"display_name": "Dr. Test"} def get_backend_url(self): return "https://example.invalid" def _empfang_self_user_id(self): return "u1" def _raise(*a, **k): raise OSError("timeout") with patch.object(sync, "_sync_headers", return_value={"X-Api-Key": "x"}), \ patch.object(sync, "_http_post", side_effect=_raise): ok, msg = sync.publish_doku_prompt(_FakeApp(), "verlauf", {"content": "x"}, "Titel") self.assertFalse(ok) self.assertEqual(msg, "__CONN_ERROR__") def test_publish_payload_includes_author_and_type(self): import aza_doku_prompt_sync as sync captured = {} class _FakeApp: _user_profile = {"display_name": "Dr. Test"} def get_backend_url(self): return "https://example.invalid" def _empfang_self_user_id(self): return "u1" def _capture(url, headers, body): captured.update(body) return (200, {"ok": True}) with patch.object(sync, "_sync_headers", return_value={"X-Api-Key": "x"}), \ patch.object(sync, "_http_post", side_effect=_capture): ok, _ = sync.publish_doku_prompt(_FakeApp(), "verlauf", {"content": "P"}, "Titel", "Beschr") self.assertTrue(ok) self.assertEqual(captured.get("doc_type"), "verlauf") self.assertEqual(captured.get("author_display"), "Dr. Test") self.assertEqual(captured.get("title"), "Titel") def test_local_publish_payload_helper(self): import tempfile import aza_doku_vorlagen as dv import aza_config with tempfile.TemporaryDirectory() as td: with patch.object(aza_config, "get_writable_data_dir", return_value=td): # dv ruft aza_config.get_writable_data_dir intern über import auf dv.save_local_publish_payload({"document_type_key": "verlauf", "title": "T"}) p = os.path.join(td, "doku_prompt_publish_queue.json") self.assertTrue(os.path.isfile(p)) with open(p, encoding="utf-8") as fh: data = json.load(fh) self.assertEqual(data[0]["document_type_key"], "verlauf") def test_publish_payload_metadata_fields(self): import tempfile import aza_doku_vorlagen as dv import aza_config with tempfile.TemporaryDirectory() as td: with patch.object(aza_config, "get_writable_data_dir", return_value=td): dv.save_local_publish_payload({ "document_type_key": "verlauf", "document_type_label": "Verlauf", "title": "Mein Verlauf", "author_display_name": "Dr. Test", "author_initials": "D.T.", "region": "Winterthur", "specialty": "Dermatologie", "description": "Beschreibungstext", "prompt_text": "Prompt", }) items = dv.load_local_prepared_public_items() self.assertEqual(len(items), 1) item = items[0] self.assertEqual(item["doc_type"], "verlauf") self.assertEqual(item["title"], "Mein Verlauf") self.assertEqual(item["author_display"], "Dr. Test") self.assertEqual(item["location"], "Winterthur") self.assertEqual(item["specialty"], "Dermatologie") self.assertEqual(item["description"], "Beschreibungstext") def test_adopt_verlauf_appears_in_dropdown_data(self): path, dv = self._patch_templates_path() dv._save(dv._default_structure()) class _FakeApp: _user_profile = {"display_name": "Dr. Test"} def _empfang_self_user_id(self): return "u1" def get_practice_id(self): return "p1" item = { "doc_type": "verlauf", "content": "Verlauf-Prompt", "title": "Öffentlicher Verlauf", "description": "Beschreibung", "author_display": "Dr. X", } new_id = dv.adopt_public_template_to_own(_FakeApp(), item, activate=True) self.assertIsNotNone(new_id) data = dv._load() verlauf_names = [t["name"] for t in data["templates"]["verlauf"] if not t.get("is_system")] kg_names = [t["name"] for t in data["templates"]["kg"] if not t.get("is_system")] self.assertIn("Öffentlicher Verlauf", verlauf_names) self.assertNotIn("Öffentlicher Verlauf", kg_names) self.assertEqual(data["active"]["verlauf"], new_id) def test_adopted_template_deletable(self): path, dv = self._patch_templates_path() dv._save(dv._default_structure()) class _FakeApp: def _empfang_self_user_id(self): return "u1" def get_practice_id(self): return "p1" item = {"doc_type": "verlauf", "content": "X", "title": "Löschbar"} new_id = dv.adopt_public_template_to_own(_FakeApp(), item, activate=True) data = dv._load() data["templates"]["verlauf"] = [ t for t in data["templates"]["verlauf"] if not (isinstance(t, dict) and t.get("id") == new_id) ] data["active"]["verlauf"] = "aza_default" dv._save(data) data2 = dv._load() names = [t["name"] for t in data2["templates"]["verlauf"] if not t.get("is_system")] self.assertNotIn("Löschbar", names) self.assertEqual(data2["active"]["verlauf"], "aza_default") def test_is_own_public_item_recognition(self): import aza_doku_vorlagen as dv class _FakeApp: _user_profile = {"display_name": "André M. Surovy"} def _empfang_self_user_id(self): return "user-andre" def get_practice_id(self): return "p1" own = {"author_user_id": "user-andre", "author_display": "André M. Surovy"} foreign = {"author_user_id": "other-user", "author_display": "Dr. Fremd"} self.assertTrue(dv.is_own_public_item(_FakeApp(), own)) self.assertFalse(dv.is_own_public_item(_FakeApp(), foreign)) def test_update_local_publish_queue_item(self): import tempfile import aza_doku_vorlagen as dv import aza_config with tempfile.TemporaryDirectory() as td: qpath = os.path.join(td, "doku_prompt_publish_queue.json") with open(qpath, "w", encoding="utf-8") as fh: json.dump([{ "document_type_key": "brief", "title": "Alt", "author_user_id": "u1", }], fh) with patch.object(aza_config, "get_writable_data_dir", return_value=td): ok = dv.update_local_publish_queue_item(0, { "title": "Neu", "document_type_key": "verlauf", "document_type_label": "Verlauf", }) items = dv.load_local_prepared_public_items() self.assertTrue(ok) self.assertEqual(items[0]["title"], "Neu") self.assertEqual(items[0]["doc_type"], "verlauf") def test_publish_dialog_has_doc_type_dropdown(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() dlg_block = src.split("def open_doku_publish_dialog", 1)[-1].split("\ndef ", 1)[0] self.assertIn("Dokumenttyp:", dlg_block) self.assertIn("doc_combo", dlg_block) self.assertIn('"doc_type": _get_selected_doc_type()', dlg_block) def test_doku_refresh_callback_registered(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn("_doku_vorlage_refresh_cb", src) self.assertIn("adopt_public_template_to_own", src) self.assertIn("refresh_doku_prompt_window", src) def test_metadata_dialog_height_and_action_bar(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() dlg_block = src.split("def open_doku_publish_dialog", 1)[-1].split("\ndef ", 1)[0] self.assertIn("btn_row.pack(side=\"bottom\"", dlg_block) self.assertIn("_PUBLISH_DLG_MIN_W, _PUBLISH_DLG_MIN_H = 650, 760", src) self.assertIn("⏺ Diktieren", dlg_block) self.assertIn("Beschreibung:", dlg_block) def test_remove_local_publish_queue_item(self): import tempfile import aza_doku_vorlagen as dv import aza_config with tempfile.TemporaryDirectory() as td: with patch.object(aza_config, "get_writable_data_dir", return_value=td): dv.save_local_publish_payload({"document_type_key": "verlauf", "title": "A"}) dv.save_local_publish_payload({"document_type_key": "brief", "title": "B"}) self.assertTrue(dv.remove_local_publish_queue_item(0)) items = dv.load_local_prepared_public_items() self.assertEqual(len(items), 1) self.assertEqual(items[0]["title"], "B") def test_filter_public_items_search(self): import aza_doku_vorlagen as dv items = [ {"doc_type": "verlauf", "title": "Alpha", "specialty": "Dermatologie", "content": "Verlaufstext", "description": ""}, {"doc_type": "brief", "title": "Beta", "specialty": "Allgemein", "content": "Brieftext", "description": ""}, ] by_name = dv.filter_public_items(items, "alpha") self.assertEqual(len(by_name), 1) self.assertEqual(by_name[0]["title"], "Alpha") by_spec = dv.filter_public_items(items, "dermatologie") self.assertEqual(len(by_spec), 1) by_prompt = dv.filter_public_items(items, "brieftext") self.assertEqual(len(by_prompt), 1) self.assertEqual(by_prompt[0]["doc_type"], "brief") def test_adopt_empty_content_returns_none_without_crash(self): path, dv = self._patch_templates_path() dv._save(dv._default_structure()) class _FakeApp: def _empfang_self_user_id(self): return "u1" def get_practice_id(self): return "p1" def after(self, _ms, fn): fn() item = {"doc_type": "verlauf", "content": "", "title": "Leer"} new_id = dv.adopt_public_template_to_own(_FakeApp(), item, activate=True) self.assertIsNotNone(new_id) def test_public_window_search_field(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() pub_block = src.split("def open_public_doku_vorlagen_window", 1)[-1].split("\ndef ", 1)[0] self.assertIn("Suchen:", pub_block) self.assertIn("filter_public_items", pub_block) def test_main_doc_type_persistence(self): import tempfile import aza_persistence as ap with tempfile.TemporaryDirectory() as td: cfg = os.path.join(td, "autotext.json") with patch.object(ap, "_autotext_config_path", return_value=cfg): self.assertEqual(ap.load_main_doc_type(), "kg") ap.save_main_doc_type("verlauf") self.assertEqual(ap.load_main_doc_type(), "verlauf") ap.save_main_doc_type("invalid_type") self.assertEqual(ap.load_main_doc_type(), "kg") ap.save_main_doc_type("brief") data = ap.load_autotext() self.assertEqual(data.get("main_doc_type"), "brief") class TestModalDialogHelpers(unittest.TestCase): def test_modal_helpers_exist(self): path = os.path.join(os.path.dirname(__file__), "aza_ui_helpers.py") with open(path, encoding="utf-8") as f: src = f.read() for name in ( "make_modal_topmost", "release_modal_dialog", "aza_showinfo", "aza_askyesno", "_restore_main_topmost", ): self.assertIn(f"def {name}", src) def test_make_modal_topmost_sets_transient_grab_topmost(self): import tkinter as tk from aza_ui_helpers import make_modal_topmost root = tk.Tk() root.withdraw() parent = tk.Toplevel(root) parent.withdraw() dlg = tk.Toplevel(parent) make_modal_topmost(dlg, parent, grab=True) self.assertEqual(str(dlg.attributes("-topmost")), "1") self.assertEqual(dlg.grab_current(), dlg) dlg.destroy() parent.destroy() root.destroy() def test_messagebox_wrapper_passes_parent(self): import tkinter as tk from unittest.mock import patch from aza_ui_helpers import aza_askyesno root = tk.Tk() root.withdraw() parent = tk.Toplevel(root) parent.withdraw() parent._main_pinned = True # type: ignore[attr-defined] captured = {} def _fake_askyesno(title, message, parent=None): captured["parent"] = parent return True with patch("tkinter.messagebox.askyesno", side_effect=_fake_askyesno): result = aza_askyesno("T", "M", parent=parent) self.assertTrue(result) self.assertIs(captured.get("parent"), parent) parent.destroy() root.destroy() def test_doku_vorlagen_uses_aza_messagebox_wrappers(self): path = os.path.join(os.path.dirname(__file__), "aza_doku_vorlagen.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn("from aza_ui_helpers import", src) self.assertIn("aza_askyesno", src) self.assertIn("make_modal_topmost", src) pub_block = src.split("def open_public_doku_vorlagen_window", 1)[-1].split("\ndef ", 1)[0] self.assertIn("aza_askyesno(", pub_block) self.assertNotIn("messagebox.askyesno", pub_block) pub_dialog = src.split("def open_doku_publish_dialog", 1)[-1].split("\ndef ", 1)[0] self.assertIn("make_modal_topmost(dlg, parent)", pub_dialog) self.assertIn("release_modal_dialog(dlg, parent)", pub_dialog) def test_bibliothek_ui_uses_aza_messagebox_wrappers(self): path = os.path.join(os.path.dirname(__file__), "aza_bibliothek_ui.py") with open(path, encoding="utf-8") as f: src = f.read() self.assertIn("aza_askyesno", src) self.assertNotIn("messagebox.", src) if __name__ == "__main__": unittest.main()