# -*- coding: utf-8 -*- """782-2 건설 공통 1장 나머지 — 규칙 · 계수만 절 계수 표 · 1-5-4 · 1-5-6 로직 · 성격 칸 · 절 목록 대조(check_master 목차).""" import copy import sys from decimal import 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 check_master_toc as toc # noqa: E402 import master_formula as mf # noqa: E402 COEF = "계수_건설품셈_01장_적용기준.json" LOGIC = "로직_건설품셈_01장_적용기준.json" WASTE, WATER = "GC001192", "GC001193" @pytest.fixture(scope="module") def whole(): return cm.master() @pytest.fixture(scope="module") def files(): return cm.load([COEF, LOGIC]) def result(whole, key, **given) -> Decimal: return mf.run(whole, key, given)["결과"] @pytest.mark.parametrize( "given, want", [ # 신축 철근콘크리트조 폐콘크리트류 0.04888 TON/㎡ × 1,000㎡ ( { "공사": "신축", "구조": "철근콘크리트조", "폐기물": "폐콘크리트류", "면적": 1000, "증가율": 0, }, "48.88", ), # 주③ 파일 시공 15% 증가 ( { "공사": "신축", "구조": "철근콘크리트조", "폐기물": "폐콘크리트류", "면적": 1000, "증가율": 15, }, "56.212", ), # 해체 아파트 혼합폐기물 0.1637 — 증가율은 폐콘크리트류만 ( {"공사": "해체", "구조": "아파트", "폐기물": "혼합폐기물", "면적": 1000, "증가율": 15}, "163.7", ), ], ) def test_환경관리비(whole, given, want): assert result(whole, WASTE, **given) == Decimal(want) def test_환경관리비_빈칸(whole): # 원문 「-」(신축 폐금속류) = 줄 없음 — 짐작 값 없이 멈춤 with pytest.raises(mf.FormulaError): result(whole, WASTE, 공사="신축", 구조="아파트", 폐기물="폐금속류", 면적=1, 증가율=0) @pytest.mark.parametrize( "given, want", [ ({"구분": "콘크리트혼합 및 양생", "작업량": 100, "잡용수율": 0}, "27"), ({"구분": "콘크리트혼합 및 양생", "작업량": 100, "잡용수율": 45}, "39.15"), ({"구분": "보통벽돌쌓기", "작업량": 2, "잡용수율": 0}, "0.36"), ], ) def test_공사용수(whole, given, want): assert result(whole, WATER, **given) == Decimal(want) def test_표_목록(files): tables = files[COEF]["표"] new = [t for t in tables if "CC000495" <= t["키"] <= "CC000527"] assert len(new) == 33 and len(tables) == 45 + 33 by_no = {} for t in new: by_no.setdefault(t["원문번호"], []).append(t["키"]) assert set(by_no) == { *("1-2-2", "1-2-3", "1-2-4", "1-2-5", "1-2-6", "1-2-8", "1-2-9", "1-3-2", "1-4-1", "1-4-2"), *(f"1-5-{n}" for n in range(1, 11)), } uses = {t["키"]: t["용도"]["로직키"] for t in new if t["용도"]["로직키"]} assert uses == {"CC000519": [WASTE], "CC000522": [WATER]} assert [r["키"] for r in files[LOGIC]["줄"]] == [ "GC001140", "GC001141", "GC001142", WASTE, WATER, ] def test_성격(files): nature = {t["키"]: t.get("성격") for t in files[COEF]["표"]} old = [f"CC{n:06d}" for n in range(1, 34)] assert all(nature[k] for k in old) # 1-3 · 1-4 표 모두 small = {k for k, v in nature.items() if v == "작업시간 제한 · 소규모"} assert small == {"CC000028", "CC000511", "CC000512"} # 1-4-6 작업시간 제한 ↔ 1-2-9 같은 성격 assert nature["CC000032"] == nature["CC000033"] # 1-4-7 기타 묶음 def test_check_master(files, whole): found = [x for name, data in files.items() for x in cm.check_form(name, data)] found += cm.check_body(files) + cm.check_logics(files, whole) + toc.check_toc(files) assert found == [] def test_목차_대조(files): rows = {r["절"]: r for r in toc.table(files)} calc = [r for r in rows.values() if r["쓰임"] == "계산 대상"] assert len(rows) == 31 and len(calc) == 27 assert all(r["계수"] or r["로직"] for r in calc) assert {k: r["표지"] for k, r in rows.items() if r["표지"]} == { "1-2-9": "783-1 로 미룸", "1-4-2": "783-1 로 미룸", } # 통째 빠진 절 · 로직 없는 품·표·식 절을 잡음 cut = copy.deepcopy(files) cut[COEF]["표"] = [t for t in cut[COEF]["표"] if t["원문번호"] != "1-5-8"] cut[LOGIC]["줄"] = [r for r in cut[LOGIC]["줄"] if r["키"] != WATER] found = toc.check_toc(cut) assert any("1-5-8" in x and "통째 빠짐" in x for x in found) assert any("1-5-6" in x and "로직 없음" in x for x in found) assert len(found) == 2