Files
Aislo/resources/tester/test_b08_structure_table_holes.py
T
eomsangdonandClaude Opus 5 2c0ae48ac7 fix(b08): 구조물 표 구멍 넷 — 골막이·바닥막이 내역 수량 0 · 떼흙막이 m당 오표시 · 개거 L형 키 · 기슭막이 거짓 사유
구조물도 남은 종류 그림을 시작하며 시험 제원으로 표를 세워 보다 드러남:
- 골막이(개소당)·바닥막이(㎡당)가 「m · 연장 0」으로 읽혀 구조물도 전 줄 「단위당 못 냄」 · 인계 「물량이 0 이라 내역에 안 세움」 → 내역 단위 개소 1 / ㎡ 면적으로
- 떼흙막이 개소당 값이 연장으로 나뉘어 떼 0.139/m 로 보였음 → 개소당 1.39
- 개거 「L형수로 H=0.2」 — 엔진 키가 「콘크리트 L형수로 H=0.2」라 등록부에서 골라도 영영 안 섰음 → 등록부 글자로
- 기슭막이 사유 「돌 종류·뒷길이 칸이 없어」 — 칸이 선 뒤로 거짓 · 돌쌓기 한 줄과 같은 말 두 번 → 걷음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
2026-09-14 06:32:14 +09:00

99 lines
4.0 KiB
Python

"""구조물도 그림을 그리려다 드러난 **표 구멍** (2026-09-14 · PLAN 12장 남은 종류 그림).
⚠ 셋 — 값이 서기는 하거나(떼흙막이) 조용히 0 이라 아무 시험도 안 잡던 자리.
① 골막이·바닥막이는 개소당·㎡당 값인데 내역 단위가 「m · 연장 0」 → **수량 0, 내역에 안 섬**
② 떼흙막이는 개소당 값이 연장으로 나뉘어 **떼 0.139/m** 로 보였음
③ 개거 「L형수로 H=0.2」 — 등록부 선택지 글자와 엔진 키가 달라 골라도 영영 안 섬
④ 기슭막이 사유 「돌 종류·뒷길이 칸이 없어」 — 칸이 선 뒤로 거짓 · 같은 말 두 번
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from B08_Quantity.B08_Quantity_Engine_Handoff import build_handoff # noqa: E402
from B08_Quantity.B08_Quantity_Engine_StructureSheet import build_standard_sheets # noqa: E402
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import build_table # noqa: E402
def _table(type_id: str, start: float, end: float, **options) -> dict:
structure = {
"structure_id": type_id,
"type_id": type_id,
"start_m": start,
"end_m": end,
"options": options,
}
return build_table([structure], None)
def _sheet(table: dict) -> dict:
return build_standard_sheets(table)["sheets"][0]
def _unit(sheet: dict, name: str) -> float:
return next(row["unit_amount"] for row in sheet["rows"] if row["name"] == name)
def test_골막이는_개소당으로_서고_내역_수량이_1_개소() -> None:
table = _table(
"erosion_check", 50, 50, form="돌", height_m=1.5, top_length_m=4, bottom_length_m=2
)
item = table["structures"][0]
assert (item["billing_unit"], item["billing_quantity"]) == ("개소", 1.0)
sheet = _sheet(table)
assert sheet["unit_label"] == "개소당" and sheet["unpriced_rows"] == []
row = next(r for r in build_handoff(unit_quantity_table=table)["work_items"] if r["unit"])
assert (row["unit"], row["quantity"]) == ("개소", 1.0) # 전: m · 0.0 → 내역에 안 섬
def test_떼흙막이는_개소당_값이_그대로_보인다() -> None:
sheet = _sheet(_table("soil_guard", 60, 70, form="떼", height_m=0.5, length_m=10))
assert sheet["unit_label"] == "개소당"
assert abs(_unit(sheet, "떼") - 1.39) < 1e-9 # 전: 0.139 (m당으로 나뉨)
def test_바닥막이는_제곱미터당() -> None:
table = _table("bed_sill", 80, 80, form="돌붙임(찰)", area_m2=12, height_m=0.3)
sheet = _sheet(table)
assert sheet["unit_label"] == "㎡당" and sheet["billing_total"] == 12
assert abs(_unit(sheet, "돌붙임") - 1.0) < 1e-9 and abs(_unit(sheet, "입적") - 0.45) < 1e-9
def test_개거_L형수로는_등록부_글자로_선다() -> None:
registry = json.loads(
(ROOT / "B05_Profile" / "B05_Profile_Structure_Types.json").read_text(encoding="utf-8")
)
choices = next(
option["choices"]
for item in registry["types"]
if item["type_id"] == "open_ditch"
for option in item["options"]
if option["key"] == "ditch_spec"
)
for choice in choices:
item = _table("open_ditch", 0, 0, ditch_spec=choice, length_m=5)["structures"][0]
assert item["components"], (choice, item["notes"])
concrete = next(
c
for c in _table("open_ditch", 0, 0, ditch_spec="L형수로 H=0.2", length_m=5)["structures"][
0
]["components"]
if c["name"] == "콘크리트"
)
assert abs(concrete["amount"] - 0.1508 * 5) < 1e-9
def test_기슭막이_사유에_없는_칸_이야기가_없다() -> None:
notes = _table("revetment", 0, 10, form="돌쌓기(찰)", height_m=2, length_m=10)["structures"][0][
"notes"
]
assert not any("칸이 없어" in note for note in notes)
assert any("뒷길이를 안 골라" in note for note in notes) # 같은 사실은 돌쌓기 한 줄이 말함