B08_Quantity 86 · B09_Estimation 111 파일을 old_code/ 로 옮김(지우지 않음). 화면은 메뉴·주소·단계 막대만 남은 빈 틀 둘 — main.py 라우터 13 개는 끊음. B07 이 빌려 쓰던 비탈 길이·면적은 필요한 함수만 B07_DesignDetail_Engine_SlopeGeometry 로 옮겨 적음(면적 적분·노면 면적·측점 묶음은 안 옮김) · 시험 하나를 새로 둠. B07 구조물도 조립(Cad_StandardSheet)은 2026-09-13 에 이미 도면 목록에서 빠져 부르는 곳이 없어 old_code 로 같이 보냄 — 구조물 그림은 되살리지 않음. B06 구조물 몫 조회는 빈 값으로 두어 화면이 그대로 서게 함. B08·B09 를 부르던 시험 25 개도 old_code/resources/tester 로 옮김. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
95 lines
3.7 KiB
Python
95 lines
3.7 KiB
Python
"""기슭막이 등록부 칸 둘 — 뒷길이·돌 종류 (2026-09-09).
|
|
|
|
⚠⚠ 왜 있나 — 칸이 없어 `_back_length` 가 **조용히 45㎝ 기본값으로 돌고** 있었다.
|
|
같은 자리에서 예전에 **키 이름 어긋남 사고**(`stone_back_length_cm` 를 읽어 저장값이
|
|
영영 안 닿음)가 있었으므로 **이름과 글자를 대조해 잠근다.**
|
|
⚠ 기본값을 두지 않는다 — 값이 없으면 「기본값으로 섰음」이 드러나야 한다.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
|
if str(PROJECT_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
|
|
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import ( # noqa: E402
|
|
BACK_LENGTH_KEYS,
|
|
STONE_KIND_OPTION,
|
|
load_stone_kind_table,
|
|
)
|
|
from common_util.common_util_drainage_pipes import ( # noqa: E402
|
|
PipePoint,
|
|
load_pipe_points,
|
|
save_pipe_points,
|
|
)
|
|
|
|
REGISTRY = json.loads(
|
|
(PROJECT_ROOT / "B05_Profile" / "B05_Profile_Structure_Types.json").read_text(encoding="utf-8")
|
|
)
|
|
|
|
|
|
def _options(type_id: str) -> dict[str, dict]:
|
|
entry = next(item for item in REGISTRY["types"] if item["type_id"] == type_id)
|
|
return {option["key"]: option for option in entry["options"]}
|
|
|
|
|
|
def test_기슭막이에_칸_둘이_있다() -> None:
|
|
options = _options("revetment")
|
|
assert "back_len_cm" in options, "뒷길이 칸이 없으면 45㎝ 기본값으로 조용히 돈다"
|
|
assert STONE_KIND_OPTION in options
|
|
|
|
|
|
def test_엔진이_읽는_이름과_같다() -> None:
|
|
"""이름이 어긋나면 저장값이 영영 안 닿는다 — 예전 사고 그대로."""
|
|
options = _options("revetment")
|
|
assert BACK_LENGTH_KEYS[0] in options
|
|
assert STONE_KIND_OPTION in options
|
|
|
|
|
|
def test_고를_수_있는_값이_품셈표와_글자까지_같다() -> None:
|
|
options = _options("revetment")
|
|
table = load_stone_kind_table()
|
|
assert options["back_len_cm"]["choices"] == [str(value) for value in table["back_lengths_cm"]]
|
|
kinds = [key for key in (table.get("backfill_ratio_of_back_length") or {}) if key != "note"]
|
|
assert options[STONE_KIND_OPTION]["choices"] == kinds
|
|
|
|
|
|
def test_기본값을_두지_않는다() -> None:
|
|
options = _options("revetment")
|
|
assert options["back_len_cm"]["default"] is None
|
|
assert options[STONE_KIND_OPTION]["default"] is None
|
|
|
|
|
|
def test_돌쌓기와_같은_값을_쓴다() -> None:
|
|
"""돌쌓기(찰·메)와 갈래가 갈리면 같은 돌인데 수량이 달라진다."""
|
|
for type_id in ("masonry_wet", "masonry_dry"):
|
|
other = _options(type_id)
|
|
revet = _options("revetment")
|
|
assert other["back_len_cm"]["choices"] == revet["back_len_cm"]["choices"]
|
|
assert other[STONE_KIND_OPTION]["choices"] == revet[STONE_KIND_OPTION]["choices"]
|
|
|
|
|
|
def test_저장했다_되읽으면_그대로_있다() -> None:
|
|
"""정본 파일을 실제로 오간다 — 관 지점 `options` 에 담겨 나가고 들어온다.
|
|
|
|
⚠ 저장 경로는 `storage/` 아래여야 한다(경로 가드). 시험용 자리를 쓰고 지운다.
|
|
"""
|
|
stored = "storage/tmp/test_revet_fields"
|
|
target = PROJECT_ROOT / stored
|
|
try:
|
|
point = PipePoint(chainage_m=85.05, source="spacing")
|
|
point.options = {"back_len_cm": "55", "stone_kind": "견치돌", "facility": "revetment"}
|
|
assert save_pipe_points(stored, "sig-1", [point]) == 1
|
|
|
|
loaded = load_pipe_points(stored, "sig-1")
|
|
assert loaded is not None and len(loaded) == 1
|
|
assert loaded[0].options["back_len_cm"] == "55"
|
|
assert loaded[0].options["stone_kind"] == "견치돌"
|
|
finally:
|
|
shutil.rmtree(target, ignore_errors=True)
|