"""사용자에게 뜨는 문구 검사 — **키 이름이 화면에 새지 않는다** (B08 ㉑). ⚠ 「`back_len_cm` 가 저장돼 있지 않아 갈래를 못 고름」처럼 개발자 키가 그대로 뜨던 자리가 있었다. 사용자는 그 이름을 모르고 무엇을 해야 하는지도 알 수 없다. ⚠ 「없다」만 말하지 않는다 — **어디서 채우면 풀리는지**까지 있어야 그 말이 쓸모 있다. """ from __future__ import annotations import re import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT)) from B08_Quantity.B08_Quantity_Engine_Handoff import build_handoff, masonry_class # noqa: E402 from B08_Quantity.B08_Quantity_Engine_UnitQuantity import build_table, expand # noqa: E402 from B08_Quantity.B08_Quantity_Wording import ( # noqa: E402 OPTION_LABELS, option_missing, spec_missing, type_label, ) #: 화면 문구에 나오면 안 되는 것 — 저장 제원 키·구조물 `type_id` 같은 개발자 이름. LEAK_PATTERN = re.compile( r"back_len_cm|stone_cm|height_m|length_m|face_slope_ratio" r"|masonry_wet|masonry_dry|boulder_masonry|retaining_wall|soil_guard|pipe_inlet_basin" ) def _notes(structures: list[dict]) -> list[str]: table = build_table(structures) return [note for item in table["structures"] for note in item["notes"]] def test_돌쌓기_뒷길이_안내가_사람_말일것() -> None: kind, why = masonry_class({}) assert kind is None assert "뒷길이" in why assert not LEAK_PATTERN.search(why), why # 어디서 채우면 되는지가 있어야 한다. assert "입력" in why def test_큰돌쌓기_직경_안내가_사람_말일것() -> None: notes = _notes([{"type_id": "boulder_masonry", "options": {"height_m": 2.0, "length_m": 10.0}}]) assert notes and "돌 직경" in notes[0] assert not LEAK_PATTERN.search(notes[0]), notes[0] def test_산출식_없는_종류_안내가_사람_말일것() -> None: notes = _notes([{"type_id": "soil_guard", "options": {"height_m": 2.0, "length_m": 10.0}}]) assert any("흙막이" in note for note in notes) assert not any(LEAK_PATTERN.search(note) for note in notes), notes def test_규격_미확보_안내가_사람_말일것() -> None: result = expand( { "type_id": "retaining_wall", "options": {"height_m": 1.6, "length_m": 10.0, "form": "반중력식"}, } ) note = next(n for n in result.notes if "규격" in n) assert "옹벽" in note and "옹벽 형식" in note assert not LEAK_PATTERN.search(note), note def test_인계_못이은_줄도_사람_말일것() -> None: unit = build_table( [ { "type_id": "soil_guard", "start_m": 0.0, "end_m": 10.0, "options": {"height_m": 2.0, "length_m": 10.0}, } ] ) unmatched = build_handoff(unit_quantity_table=unit)["unmatched_work_items"] assert unmatched and "흙막이" in unmatched[0] assert not any(LEAK_PATTERN.search(item) for item in unmatched), unmatched def test_모르는_키는_지어내지_않을것() -> None: """⚠ 잘못된 안내가 없는 안내보다 나쁘다 — 모르면 키를 그대로 보인다.""" text = option_missing("듣도보도못한키") assert "듣도보도못한키" in text def test_라벨표에_어디서_채우는지가_있을것() -> None: for key, (label, where) in OPTION_LABELS.items(): assert label and label != key, key assert isinstance(where, str) def test_이름표에_없으면_원래_값을_보일것() -> None: assert type_label("듣도보도못한종류") == "듣도보도못한종류" assert type_label("masonry_wet") == "돌쌓기(찰)" # 레지스트리 이름이 있으면 그것이 먼저다. assert type_label("masonry_wet", {"masonry_wet": "돌쌓기(찰쌓기)"}) == "돌쌓기(찰쌓기)" def test_자료가_통째로_없으면_그렇게_말할것() -> None: assert "표준 물량 자료" in spec_missing("box_culvert", [])