Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
111 lines
4.3 KiB
Python
111 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""「칸은 있는데 표가 안 읽음」 — 등록부 칸 옆에 「아직 표에 안 쓰임」 (2026-09-14 브레인 차례 ①).
|
|
|
|
사용자가 값을 넣어도 수량·금액이 아무것도 안 바뀌는 칸. 사유를 표에만 두지 말고 칸 옆에도 보임
|
|
(브레인 판정 ③ 「B」). 표시가 참말인지 **값을 바꿔 돌려 보고** 지킴 — 표가 그 칸을 읽기 시작하면
|
|
여기서 깨지고, 그때 표시를 걷음(표시가 거짓말로 남지 않게).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
if str(ROOT) not in sys.path:
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from B05_Profile.B05_Profile_Structures_Schema import structure_type_map # noqa: E402
|
|
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import build_table # noqa: E402
|
|
|
|
#: 종류 → (표가 서는 기준 제원, 안 읽는 칸). 2026-09-14 값을 바꿔 전수 대조한 결과.
|
|
#: ⚠ 기초(foundation)·높이는 인계 구조물터파기 심도 구간이 읽어 뺌 · 단 수·올림·이동은 횡단도 칸이라 뺌.
|
|
MARKED: dict[str, tuple[dict, list[str]]] = {
|
|
"erosion_check": (
|
|
{"height_m": 2.0, "top_length_m": 6.0, "bottom_length_m": 4.0, "form": "돌"},
|
|
["thickness_top_m", "thickness_bottom_m", "stone_supply", "stone_coeff_basis"],
|
|
),
|
|
"bed_sill": (
|
|
{"area_m2": 10.0, "form": "돌붙임(찰)"},
|
|
["stone_supply", "stone_coeff_basis", "fill_concrete_mpa", "face_slope_ratio"],
|
|
),
|
|
"boulder_masonry": (
|
|
{"height_m": 2.5, "length_m": 10.0, "stone_cm": "60~80", "bond": "찰쌓기"},
|
|
[
|
|
"stone_supply",
|
|
"stone_coeff_basis",
|
|
"fill_concrete_mpa",
|
|
"weep_hole_diameter_mm",
|
|
"weep_hole_area_m2",
|
|
],
|
|
),
|
|
"soil_guard": (
|
|
{"height_m": 1.0, "length_m": 10.0, "form": "떼"},
|
|
[
|
|
"thickness_top_m",
|
|
"thickness_bottom_m",
|
|
"back_len_cm",
|
|
"stone_kind",
|
|
"stone_supply",
|
|
"stone_coeff_basis",
|
|
"fill_concrete_mpa",
|
|
"face_slope_ratio",
|
|
"weep_hole_diameter_mm",
|
|
"weep_hole_area_m2",
|
|
],
|
|
),
|
|
}
|
|
|
|
FIELDS = (ROOT / "B05_Profile" / "B05_Profile_UI_Structures_Fields.ts").read_text(encoding="utf-8")
|
|
PANEL = (ROOT / "B05_Profile" / "B05_Profile_UI_Structures_Panel.ts").read_text(encoding="utf-8")
|
|
|
|
|
|
def _snapshot(type_id: str, options: dict) -> str:
|
|
structure = {
|
|
"structure_id": "p",
|
|
"type_id": type_id,
|
|
"start_m": 0.0,
|
|
"end_m": 10.0,
|
|
"chainage_m": 5.0,
|
|
"options": options,
|
|
}
|
|
table = build_table([structure], {}, {5.0: "both_fill"}, None, 0.2)
|
|
# 저장 제원을 그대로 되돌려 싣는 칸(`options`)은 뺌 — 값이 **표에 닿았는지**만 봄.
|
|
for row in table["structures"]:
|
|
row.pop("options", None)
|
|
return json.dumps(table, ensure_ascii=False, sort_keys=True, default=str)
|
|
|
|
|
|
def _probe_values(option) -> list:
|
|
if option.choices:
|
|
return list(option.choices)
|
|
return [0.73, 1.37] if option.input == "number" else ["x"]
|
|
|
|
|
|
@pytest.mark.parametrize("type_id", sorted(MARKED))
|
|
def test_등록부에_표시가_있다(type_id: str) -> None:
|
|
options = {option.key: option for option in structure_type_map()[type_id].options}
|
|
for key in MARKED[type_id][1]:
|
|
note = options[key].not_in_table
|
|
assert note and "아직 표에 안 쓰임" in note, f"{type_id}.{key}"
|
|
|
|
|
|
@pytest.mark.parametrize("type_id", sorted(MARKED))
|
|
def test_표시한_칸은_정말_안_읽힌다(type_id: str) -> None:
|
|
base, keys = MARKED[type_id]
|
|
options = {option.key: option for option in structure_type_map()[type_id].options}
|
|
reference = _snapshot(type_id, dict(base))
|
|
assert '"components": []' not in reference, "기준 제원으로 표가 안 섬 — 시험이 무의미"
|
|
for key in keys:
|
|
for value in _probe_values(options[key]):
|
|
assert _snapshot(type_id, {**base, key: value}) == reference, (
|
|
f"{type_id}.{key}={value!r} 로 표가 바뀜 — 이제 읽힘, 표시를 걷을 것"
|
|
)
|
|
|
|
|
|
def test_폼_칸_이름에_붙는다() -> None:
|
|
assert "not_in_table" in FIELDS and "not_in_table" in PANEL
|