Files
zyt/app/tests/test_diagnosis_terms.py
2026-08-28 18:24:37 +08:00

145 lines
5.6 KiB
Python

"""诊单字典 / 枚举 / 时间戳翻译的契约。"""
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