Files
Aislo/resources/tester/test_masterdata_check.py
T
eomsangdonandClaude Opus 5 bb89ffebc0 feat(master_data): 산림품셈 9장 로직 — 돈 로직 27 · 작업량 로직 20
- 로직_산림품셈_9장.json: 굴착기 0.7㎥ 작업량 식 절 · 인력 10%+기계 90% 터파기·되메우기 · 인력 절 · 철근절단 · 면고르기 · 뿌리다듬기 · 제근
- 불도저·플레이트콤펙터 절은 작업량만(기계 요소 없음)
- 계수_산림품셈_9장.json: 절별 굴착기 규격 · 인력·장비 비율 · 9-3-2 주④ f 표 12개
- master_formula: 범위규칙 「이상·미만」 · 분수 글자 값(「1/1.30」) 계산
- 시험: 이상·미만 경계 · 분수 값 · 9장 계수 표 본문 대조

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
2026-09-19 16:14:43 +09:00

137 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""마스터 데이터 검사 도구 — 견본 셋 손 계산 · 견본 파일 검사 통과 (`resources/master_data/scripts/check_master.py`)."""
import sys
from decimal import ROUND_HALF_UP, Decimal
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "master_data/scripts"))
import check_master as cm # noqa: E402
import master_formula as mf # noqa: E402
SAMPLES = [
"계수_건설품셈_공통8장.json",
"계수_산림품셈_9장.json",
"기계_건설품셈.json",
"로직_건설품셈_공통8장.json",
"로직_산림품셈_13장.json",
"로직_산림품셈_9장.json",
"소요량_산림품셈_13장.json",
]
EXCAVATOR = "건설품셈:8 굴착기(무한궤도) 시간당 경비"
@pytest.fixture(scope="module")
def whole():
return cm.master()
def cents(x) -> str:
return str(Decimal(x).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
def test_메쌓기(whole):
got = mf.run(
whole,
"산림품셈:13-4-1 메쌓기",
{"뒷길이": 35, "돌": "견치돌", "쌓기": "골쌓기", "높이": 2, "초과증가율": 80},
)
assert cents(got["계"]) == "203281.20"
def test_메쌓기_높이_증가율(whole):
got = mf.run(
whole,
"산림품셈:13-4-1 메쌓기",
{"뒷길이": 35, "돌": "견치돌", "쌓기": "골쌓기", "높이": 5, "초과증가율": 80},
)
assert [line["수량"] for line in got["줄"]] == [Decimal("0.70"), Decimal("0.56")]
def test_굴착기(whole):
got = mf.run(
whole, EXCAVATOR, {"기계": "0201-0070", "지역": "전국평균", "보정작업": "해당 없음"}
)
assert [cents(got[k]) for k in ("노무비", "재료비", "경비", "계")] == [
"35412.13",
"26130.11",
"24554.00",
"86096.24",
]
def test_굴착기_암석_보정(whole):
got = mf.run(
whole,
EXCAVATOR,
{"기계": "0201-0070", "지역": "전국평균", "보정작업": "암석작업(연암・보통암・경암)"},
)
assert got["중간"]["손료"] == 28322
assert cents(got["계"]) == "89864.24"
def test_노체포설(whole):
assert mf.run(whole, "산림품셈:9-16-1 노체포설 작업량", {})["결과"] == Decimal("24.255")
got = mf.run(whole, "산림품셈:9-16-1 노체포설", {"지역": "전국평균", "보정작업": "해당 없음"})
assert [cents(got[k]) for k in ("노무비", "재료비", "경비", "계")] == [
"1459.99",
"1077.31",
"1012.33",
"3549.63",
]
def test_범위규칙_이상_미만(whole):
"""9-2 횡단경사 「60% 미만 · 60% 이상」 — 60 은 윗줄."""
qty = [
mf.run(whole, "산림품셈:9-2 노선 굴진 보조원", {"횡단경사": x})["줄"][0]["수량"]
for x in (59.9, 60)
]
assert qty == [5, 10]
def test_분수_글자_값(whole):
"""9-4-2 f 원문 「1/1.40」 — 3600×0.7×0.55×(1/1.40)×0.35/20."""
assert mf.run(whole, "산림품셈:9-4-2 암절취 집토 작업량", {})["결과"] == Decimal("17.325")
def test_범위_입력은_막음(whole):
with pytest.raises(mf.FormulaError):
mf.run(
whole,
"산림품셈:13-4-1 메쌓기",
{"뒷길이": 35, "돌": "견치돌", "쌓기": "골쌓기", "높이": 8, "초과증가율": 120},
)
def test_견본_파일_검사_통과(whole):
files = cm.load(SAMPLES)
assert len(files) == len(SAMPLES)
assert [x for name, data in files.items() for x in cm.check_form(name, data)] == []
# 9장 계수 표는 같은 절의 소요량 표와 함께 대조 — 소요량 파일 자체의 알림은 그 창 몫
with_09 = files | cm.load(["소요량_산림품셈_09장.json"])
assert [x for x in cm.check_body(with_09) if not x.startswith("소요량_산림품셈_09장")] == []
assert cm.check_logics(files, whole) == []
def test_로직_검사가_틀린_열쇠를_잡음(whole):
row = {
"열쇠": "시험",
"입력": [{"이름": "지역", "고르기": ["전국평균", "없는곳"]}],
"중간": [{"이름": "x", "식": "찾기(계수:산림품셈:9-16-1 노체포설, 없는조건='K').적용"}],
"호표": [
{"종류": "재료", "요소": "재료:오피넷유가:경유:{지역}", "수량": "y", "비목": "재료비"}
],
"덧줄": [],
}
found, _ = mf.check_logic(whole, "산림품셈", row)
assert any("없는조건" in x for x in found)
assert any("경유:없는곳" in x for x in found)
assert any("「y」" in x for x in found)
def test_돌고_도는_참조():
assert mf.find_loops({"가": {"나"}, "나": {"가"}}) == [["가", "나", "가"]]