"""诊单字典 / 枚举 / 时间戳翻译的契约。""" from __future__ import annotations from typing import Any import pytest from doctor_workstation.services.mock_repository import DemoDoctorRepository from doctor_workstation.services.repository import RemoteDoctorRepository from doctor_workstation.ui.diagnosis_terms import ( DICTIONARY_TYPES, MULTI_VALUE_DICTIONARIES, SINGLE_VALUE_DICTIONARIES, TermIndex, format_timestamp, unit_suffix, ) def test_seed_dictionary_translates_codes_admin_shows_in_chinese() -> None: terms = TermIndex() assert terms.dictionary_label("appetite", "dry,bitter") == "干、苦" assert terms.dictionary_label("appetite", ["dry", "greasy"]) == "干、腻" assert terms.dictionary_label("weight_change", "lose_10_jin") == "瘦10斤" assert terms.dictionary_label("fatty_liver_degree", "mild") == "轻度" assert terms.dictionary_label("past_history", "hypertension、diabetes") == "高血压、糖尿病" # 同一个 code 在不同字典里含义不同,翻译必须按字段所属字典走。 assert terms.dictionary_label("skin_condition", "dry") == "干燥" assert terms.dictionary_label("eye_condition", "dry") == "干涩" # 不在字典里的自定义值回显原值,不会被吞掉。 assert terms.dictionary_label("appetite", "自定义症状") == "自定义症状" assert terms.dictionary_label("remark", "任意文本") is None def test_backend_text_field_wins_over_dictionary_and_raw_value() -> None: terms = TermIndex() assert terms.display({"appetite": "dry", "appetite_text": "口干"}, "appetite") == "口干" assert terms.display({"appetite": "dry"}, "appetite") == "干" assert terms.display({}, "appetite", default="未记录") == "未记录" def test_live_dictionary_overrides_the_bundled_seed() -> None: terms = TermIndex() terms.merge({"appetite": [{"name": "口干", "value": "dry"}]}) assert terms.dictionary_label("appetite", "dry") == "口干" # 实时字典没覆盖到的条目继续用种子。 assert terms.dictionary_label("appetite", "bitter") == "苦" def test_enum_and_timestamp_fields_render_like_the_admin_readonly_page() -> None: terms = TermIndex() assert terms.value_label("gender", 1) == "男" assert terms.value_label("gender", "0") == "女" assert terms.value_label("marital_status", "1") == "已婚" assert terms.value_label("allergy_history", "0") == "无" assert terms.value_label("family_history", 1) == "有" assert terms.value_label("diagnosis_type", "follow_up") == "复诊" assert terms.value_label("create_source", "admin") == "后台创建" assert terms.value_label("source", "1") == "患者自录" assert terms.value_label("create_time", 1783838927) == format_timestamp(1783838927) assert format_timestamp(1783838927) is not None assert format_timestamp("2026-08-18 09:20") is None assert format_timestamp(0) is None def test_units_only_decorate_numeric_readonly_values() -> None: assert unit_suffix("height", "162") == " cm" assert unit_suffix("fasting_blood_sugar", "8.2") == " mmol/L" assert unit_suffix("diabetes_discovery_year", "6") == "年" # 自由文本("17多"、"五年")不补单位,避免拼出错误的读数。 assert unit_suffix("fasting_blood_sugar", "17多") == "" assert unit_suffix("diabetes_discovery_year", "五年") == "" assert unit_suffix("remark", "123") == "" def test_dictionary_types_cover_every_field_the_backend_translates() -> None: # 与 AppointmentLogic::enrichDiagnosisLabels 的字段表保持同步。 assert set(SINGLE_VALUE_DICTIONARIES) == { "diagnosis_type", "syndrome_type", "diabetes_type", "water_intake", "weight_change", "fatty_liver_degree", } assert set(MULTI_VALUE_DICTIONARIES) == { "past_history", "appetite", "diet_condition", "body_feeling", "sleep_condition", "eye_condition", "head_feeling", "sweat_condition", "skin_condition", "urine_condition", "stool_condition", "kidney_condition", } assert set(DICTIONARY_TYPES) == set(SINGLE_VALUE_DICTIONARIES.values()) | set( MULTI_VALUE_DICTIONARIES.values() ) class _RecordingClient: def __init__(self, payload: Any) -> None: self.payload = payload self.get_calls: list[tuple[str, dict[str, Any]]] = [] def get(self, endpoint: str, params: dict[str, Any] | None = None) -> Any: self.get_calls.append((endpoint, dict(params or {}))) return self.payload def test_remote_batches_every_dictionary_into_one_request() -> None: client = _RecordingClient( { "appetite": [{"name": "口干", "value": "dry"}], "weight_change": [{"name": "瘦10斤", "value": "lose_10_jin"}], } ) repository = RemoteDoctorRepository(client) # type: ignore[arg-type] dictionaries = repository.get_dictionaries(["appetite", "weight_change", "appetite", ""]) assert client.get_calls == [("config/dict", {"type": "appetite,weight_change"})] assert list(dictionaries) == ["appetite", "weight_change"] terms = TermIndex() terms.merge(dictionaries) assert terms.dictionary_label("appetite", "dry") == "口干" @pytest.mark.parametrize("dictionary_type", DICTIONARY_TYPES) def test_demo_repository_answers_the_batch_dictionary_contract(dictionary_type: str) -> None: repository = DemoDoctorRepository() dictionaries = repository.get_dictionaries(DICTIONARY_TYPES) assert dictionary_type in dictionaries