- build_table 이 양식 있는 종류(찰쌓기) 성분을 양식 풀이 값으로 갈음. 양식 없는 종류는 전개 그대로 - 구조물에 library_item — 원단위 탭 「양식」·구조물도 머리 「양식 있음/없음」으로 가림 - 뒤 단계가 아직 이름으로 찾으므로 돌 줄은 종류 이름으로 넘김(1장 코드 잇기 뒤 걷을 자리) · 자료 출처·근거 문구는 전개 것을 그대로 둠 - 검증 프로젝트 전·후 대조: 구조물 5 중 찰쌓기 2 갈음 · 움직인 값 없음 · 자재총괄 최대 차 7e-15 · 채집석 공제 58.674·잔토 91.75 그대로. Node 가 안 돌면 전개 값 + 사유 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
89 lines
3.6 KiB
Python
89 lines
3.6 KiB
Python
"""`build_table` 이 양식 있는 종류를 양식으로 갈음 — 값은 전개와 같고 흐름은 그대로.
|
|
|
|
2026-09-13, PLAN 3장 ④-2. 겨누는 것 넷
|
|
① 찰쌓기 성분이 양식 풀이 값으로 섬 · 구조물에 `library_item` 이 붙음(양식 있음/없음)
|
|
② 값·이름·규격·갈 곳이 전개와 같음 — 자재총괄·토공집계 갈래가 안 바뀜(브레인 챙길 것 ③)
|
|
③ 양식 없는 종류(메쌓기)는 전개 그대로 · `library_item` 빔
|
|
④ 배합 성분이 자재총괄로 새지 않음(명세 6장·15장)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from B08_Quantity.B08_Quantity_Engine_MaterialSummary import ( # noqa: E402
|
|
build_table as build_material_table,
|
|
)
|
|
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import MIX_COMPONENTS, build_table # noqa: E402
|
|
|
|
pytestmark = pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
|
|
|
|
|
|
def _structures() -> list[dict]:
|
|
return [
|
|
{
|
|
"structure_id": "wet",
|
|
"type_id": "masonry_wet",
|
|
"start_m": 80.0,
|
|
"end_m": 90.0,
|
|
"options": {
|
|
"height_m": 2.5,
|
|
"length_m": 10,
|
|
"foundation": "기초유",
|
|
"stone_kind": "야면석·호박돌",
|
|
},
|
|
},
|
|
{
|
|
"structure_id": "dry",
|
|
"type_id": "masonry_dry",
|
|
"start_m": 140.0,
|
|
"end_m": 150.0,
|
|
"options": {"height_m": 2, "length_m": 10, "back_len_cm": 35},
|
|
},
|
|
]
|
|
|
|
|
|
def test_양식_갈음은_값을_안_움직인다() -> None:
|
|
names = {"masonry_wet": "돌쌓기(찰)", "masonry_dry": "돌쌓기(메)"}
|
|
before = build_table(_structures(), names, None, None, 0.2, use_templates=False)
|
|
after = build_table(_structures(), names, None, None, 0.2)
|
|
|
|
wet_before, dry_before = before["structures"]
|
|
wet_after, dry_after = after["structures"]
|
|
assert wet_after["library_item"] == "돌쌓기(찰)"
|
|
assert dry_after["library_item"] == "" # 양식 없음 — 전개 그대로
|
|
assert dry_after["components"] == dry_before["components"]
|
|
|
|
assert len(wet_after["components"]) == len(wet_before["components"])
|
|
for got, want in zip(wet_after["components"], wet_before["components"]):
|
|
assert (got["name"], got["unit"], got["destination"], got["spec"]) == (
|
|
want["name"],
|
|
want["unit"],
|
|
want["destination"],
|
|
want["spec"],
|
|
)
|
|
assert got["amount"] == pytest.approx(want["amount"], rel=1e-9, abs=1e-12), got["name"]
|
|
# 돌 줄은 뒤 단계가 찾는 종류 이름으로(1장 코드 잇기 끝나기 전) · 관측 출처는 그대로.
|
|
stone = next(c for c in wet_after["components"] if c["name"] == "야면석·호박돌")
|
|
assert stone["source"] == "uljin_library"
|
|
|
|
|
|
def test_자재총괄_갈래와_배합_성분() -> None:
|
|
names = {"masonry_wet": "돌쌓기(찰)", "masonry_dry": "돌쌓기(메)"}
|
|
before = build_material_table(
|
|
build_table(_structures(), names, None, None, 0.2, use_templates=False)
|
|
)
|
|
after = build_material_table(build_table(_structures(), names, None, None, 0.2))
|
|
rows = lambda table: {(r["name"], r["unit"]): r["total_amount"] for r in table["rows"]} # noqa: E731
|
|
assert rows(after).keys() == rows(before).keys()
|
|
for key, value in rows(before).items():
|
|
assert rows(after)[key] == pytest.approx(value, rel=1e-9), key
|
|
assert not any(name in MIX_COMPONENTS for name, _unit in rows(after))
|