"""버림 콘크리트 — 빠뜨리고 있던 줄 (2026-09-09 사용자 확정 ⑭). ⚠ 겨누는 것 다섯 ① 기본은 **넣는다** — 정한 적 없는 프로젝트에서 줄이 사라지지 않아야 한다 ② 「안 넣음」으로 두면 **빠진다** ③ 두께는 **0.10m**(KDS 44 90 00) — 임의 값이 아니다 ④ 근거 문구에 **잠정임이 드러난다**(폭이 잡석다짐 폭이라야 하나 그 값이 아직 없다) ⑤ ⚠ 채움 콘크리트와 **섞이지 않는다** — 타설 줄은 버림 몫만 세운다 """ from __future__ import annotations 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 # noqa: E402 from B08_Quantity.B08_Quantity_Engine_UnitQuantity import ( # noqa: E402 BLINDING_THICKNESS_M, boulder_masonry, stone_masonry, wants_blinding, ) def 성분(**options: object) -> dict: components, _ = stone_masonry( 2.5, 10.0, {"height_m": 2.5, "length_m": 10.0, "back_len_cm": 45, **options}, wet=True ) return {c.name: c for c in components} def test_기본은_넣는다() -> None: """⚠ 빈 칸을 「빼기」로 읽으면 저장해 둔 적 없는 프로젝트에서 줄이 통째로 사라진다.""" assert wants_blinding({}) is True assert "버림콘크리트" in 성분() def test_안_넣음으로_두면_빠진다() -> None: for value in ("안 넣음", "제외", "false", "no"): assert wants_blinding({"blinding_concrete": value}) is False, value assert "버림콘크리트" not in 성분(blinding_concrete="안 넣음") def test_두께는_원문값이다() -> None: """KDS 44 90 00 「구조물 시공이 원활하도록 **100 mm 두께**의 버림콘크리트를 타설」.""" assert BLINDING_THICKNESS_M == 0.10 got = 성분()["버림콘크리트"] # 기초 폭(터파기 폭) × 연장 × 두께 — 폭이 근거 문구에 적혀 있으므로 그 값으로 검산한다. assert got.unit == "㎥" assert got.amount > 0 def test_폭은_하단_길이에서_온다() -> None: """⚠ 「폭은 잡석다짐 폭」(KCS 34 50 05)이고 그 폭이 확정 ⑪ 로 **하단 길이**가 됐다. 옛 잠정(터파기 폭 = 평균두께 + 0.2)을 지운 자리다 — 근거 문구에 어디서 온 폭인지 적힌다. """ got = 성분()["버림콘크리트"] 하부두께 = 0.45 + 0.30 + 0.30 * (2.5 - 1.0) # 1.20 assert abs(got.amount - 하부두께 * 10.0 * BLINDING_THICKNESS_M) < 1e-9 assert "KDS" in got.basis and "하단 길이" in got.basis assert "잠정" not in got.basis def test_기초잡석은_두께가_없어_안_선다() -> None: """⚠ 폭은 생겼지만 **두께가 원문에 없다** — 지어내지 않고 사유로 드러낸다.""" _, notes = stone_masonry( 2.5, 10.0, {"height_m": 2.5, "length_m": 10.0, "back_len_cm": 45}, wet=True ) assert any("기초잡석(12-25)" in n and "두께가 원문에 없음" in n for n in notes) def test_큰돌쌓기에도_선다() -> None: components, _ = boulder_masonry( 2.5, 10.0, {"height_m": 2.5, "length_m": 10.0, "stone_cm": "60~80"} ) assert any(c.name == "버림콘크리트" for c in components) def test_타설_줄은_버림_몫만_센다() -> None: """⚠ 채움 콘크리트가 섞이면 이중계상 — 그 공종 품에 이미 들어 있을 수 있다.""" item = 성분() structure = { "structure_id": "s1", "type_id": "masonry_wet", "name": "돌쌓기(찰)", "length_m": 10.0, "height_m": 2.5, "start_m": 0.0, "end_m": 10.0, "options": {"height_m": 2.5, "length_m": 10.0, "back_len_cm": 45}, "notes": [], "components": [ {"name": c.name, "unit": c.unit, "amount": c.amount, "basis": c.basis} for c in item.values() ], } rows = build_handoff(unit_quantity_table={"structures": [structure]})["work_items"] placing = [row for row in rows if row["name"] == "콘크리트 타설"] assert len(placing) == 1 assert abs(placing[0]["quantity"] - item["버림콘크리트"].amount) < 1e-6 assert abs(placing[0]["quantity"] - item["채움콘크리트"].amount) > 1e-6