Files
Aislo/resources/tester/test_m02_hopyo_finger.py
T
eomsangdonandClaude Opus 5.5 e9e949112c feat(일위대가실무): 338-1 맞춤 핵심 서버 1 단계 — 엑셀 지문 · 우리 로직 지문 캐시 · 옵션 거꾸로 · 순위 · 판정 · 조합 · 뒤 셈 + 정답 표
- 새 파일 — Words(식 풀기 · 장비 갈래 · 조건 낱말) · Finger(블록 글 · STmate 자원 → 지문 · 기계 줄 · 직접 줄 호표) · Shares(절 몫 벡터) · Ours(마스터 판 열쇠 · 우리 지문 캐시 tmp/m02_hopyo · 엔진 셈 캐시 · 자재 값 찾기 건너뜀) · Option(옵션 공간 · 거꾸로 찾기 · 견줌) · Fit(손잡이 한 곳 · 순위 · 뒤 셈 · 맞춤셈 캐시) · Combine(조합 · 섞인 줄 몫 먼저) · Verdict(블록 셈 · 맞음 / 다른 점 / 후보)
- Match — b_order(이름 · 근거 차례 · 같음 근거 검사 · 옛 판 글 · 조항 오타) · clause(윗마디 0.9 · 나 창 Basis.clause 있으면 그것) · 이름 후보 로직은 접지 않음
- 정답 표 fixtures/m02_hopyo_golden.json(사람 136 · 새 파일 51) · 골든 도우미
- 북부청 92 줄 실측 — 1순위 87 · 다섯 안 91 · 맞음 41 틀림 0 · 다른 점 28 틀림 0 · 조합 맞음 57/66 · 우리 지문 셈 37 초 · 캐시 읽기 0.05 초

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
2026-10-15 23:36:23 +09:00

148 lines
6.7 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.
"""338-1 엑셀 지문(`M02_Hopyo_Finger` · `_Words` · `_Shares`) — 식 풀기 일곱 꼴 · 합판 지문 · 고임돌
섞음 ·
몫 · STmate 자원 · 기계 줄 · 직접 줄 호표. 실물 = 북부청 임도(읽기만)."""
import pytest
from M02_MasterTemplete import M02_Hopyo_Finger as finger
from M02_MasterTemplete import M02_Hopyo_Shares as shares
from M02_MasterTemplete.M02_Hopyo_Words import conds, mtypes, parse_rhs
from resources.tester.helper_m02_hopyo_golden import line_of
approx = pytest.approx
# ── 식 풀기 ────────────────────────────────────────────────────────────
def test_식_단가_떼고_품():
got = parse_rhs("273,540 × 3인 ÷ 55㎥ × 2 = 29,840.7")
assert got["단가"] == 273540 and got["품"] == approx(0.10909, abs=1e-5) and got["율"] == []
def test_식_퍼센트_율():
got = parse_rhs("59,020 ÷ 23.1 × 90% = 2,299.5")
assert got["품"] == approx(0.03896, abs=1e-5)
assert got["밑품"] == approx(1 / 23.1) and got["율"] == [[0.9, "%"]]
def test_식_인당_단위_섞음():
got = parse_rhs("172,068 × 0.3인/㎥ × 10% = 5,162")
assert got["품"] == approx(0.03) and got["밑품"] == approx(0.3)
def test_식_바꿔_쓴_식은_앞_율을_이어받음():
got = parse_rhs("215,907 × 4인 ÷ P × 1.2(할증) = 215,907 × 0.104 × 1.2 = 26,945")
assert got["품"] == approx(0.1248) and got["밑품"] == approx(0.104)
assert got["율"] == [[1.2, "할증"]]
def test_식_횟수_품할증():
got = parse_rhs("172,068 × 0.05인 × 2회 = 17,206")
assert got["품"] == approx(0.1) and got["밑품"] == approx(0.05) and got["율"] == [[2.0, "회"]]
got = parse_rhs("273,540 × 0.1 × 1.2(품할증) = 32,824")
assert got["밑품"] == approx(0.1) and got["율"] == [[1.2, "품할증"]]
def test_식_못_풀면_역산():
assert parse_rhs("273,540 × P = 30,000") is None
block = {"번": 1, "이름": "시험", "단위": "㎥", "글": [" 특별인부 : 273,540 × P = 27,354"]}
fp = finger.excel(block, {"이름": "시험", "규격": "", "단위": "㎥"})
assert fp["인력"]["특별인부"]["품"] == approx(0.1) and fp["인력"]["특별인부"]["어떻게"] == [
"역산"
]
def test_장비_갈래_조건_낱말():
assert mtypes("유압식 백호우 0.7㎥") == {"굴착기"} and mtypes("펌프카 41m") == {"콘크리트펌프"}
assert conds("합판거푸집 4회 보통")["횟수"] == {"4회"}
assert conds("구조물터파기(암)")["토질"] == {"암"}
# ── 실물 지문 ──────────────────────────────────────────────────────────
def test_합판_4회_지문():
block, line = line_of("N001")
fp = finger.excel(block, line)
assert fp["인력"]["형틀목공"]["품"] == approx(0.1111, abs=1e-4)
assert fp["인력"]["보통인부"]["품"] == approx(0.0444, abs=1e-4)
assert "4회" in fp["조건"]["횟수"] and fp["출처"] == [["건설품셈", "6-3-1"]]
assert {m["이름"][:4] for m in fp["자재"] if m["품"]} >= {"내수합판"}
def test_레미콘_소량_지문_장비_시간():
block, line = line_of("N000")
fp = finger.excel(block, line)
assert fp["인력"]["콘크리트공"]["품"] == approx(0.10909, abs=1e-5)
assert [(m["갈래"], round(m["시간"], 2)) for m in fp["장비"]] == [(["굴착기"], 0.29)]
def test_고임돌_섞음_율과_몫():
block, line = line_of("N005")
fp = finger.excel(block, line)
labor = fp["인력"]["보통인부"]
assert labor["밑품"] == approx(0.3, abs=1e-3) and labor["품"] == approx(0.03, abs=1e-3)
assert any(note in ("%", "섞음") and v == approx(0.1) for v, note in labor["율"])
parts = fp["몫"]
assert any(p["노임"] and not p["장비"] for p in parts) # 인력 몫
assert any(p["장비"] and not p["노임"] for p in parts) # 장비 몫
def test_몫_절마다_노임_장비():
texts = [
" 1. 굴착기 0.6㎥ 채집(90%)",
" 노무비 : 59,020 ÷ 23.1 × 90% = 2,299",
" 2. 인력채집(10%)",
" 보통인부 : 172,068 × 0.3인/㎥ × 10% = 5,162",
" 3. 합 계",
" 보통인부 : 172,068 × 1 = 172,068",
]
parts = shares.sections(texts)
assert [p["제목"] for p in parts] == ["굴착기 0.6㎥ 채집(90%)", "인력채집(10%)"]
assert parts[0]["장비"] == {"굴착기|0.6": approx(0.9 / 23.1)}
assert parts[1]["노임"] == {"보통인부": approx(0.03)}
def test_STmate_자원_지문():
block = {
"글": ["잔토처리 (기계100%) 건설표준품셈9-3", "q = 0.7 , K = 0.9"],
"자원": [
{"갈래": "L", "코드": "L00002", "이름": "보통인부", "규격": "", "품": 0.2},
*[
{
"갈래": "X",
"코드": "X00205",
"이름": "굴삭기(무한궤도)",
"규격": "0.7㎥",
"품": 0.0229,
}
]
* 3,
{"갈래": "M", "코드": "M00001", "이름": "모래", "규격": "", "품": 1.2},
],
}
fp = finger.excel(block, {"이름": "잔토처리", "규격": "토사", "단위": "M3"})
assert fp["인력"] == {"보통인부": {"품": 0.2, "밑품": 0.2, "율": [], "어떻게": ["QTY"]}}
assert [(m["갈래"], m["규격"], m["시간"]) for m in fp["장비"]] == [(["굴착기"], [0.7], 0.0229)]
assert fp["자재"] == [{"이름": "모래", "품": 1.2, "밑품": 1.2}] and fp["계수"]["K"] == 0.9
def test_기계_줄_블록_없음():
fp = finger.excel(None, {"이름": "콘크리트 펌프차", "규격": "41m,80~95㎥/hr", "단위": "hr"})
assert [(m["갈래"], m["시간"]) for m in fp["장비"]] == [(["콘크리트펌프"], 1.0)]
assert 41.0 in fp["장비"][0]["규격"] and fp["인력"] == {}
def test_직접_줄_호표():
hopyo = {
"이름": "돌붙임",
"규격": "",
"단위": "㎡",
"줄": [
{"이름": "석 공", "규격": "", "수량": 0.1, "단위": "인", "갈래": "기타"},
{"이름": "보통인부", "규격": "", "수량": 0.05, "단위": "인", "갈래": "기타"},
{"이름": "굴착기", "규격": "0.6㎥", "수량": 0.2, "단위": "hr", "갈래": "기계"},
],
}
fp = finger.direct(hopyo)
assert fp["인력"]["석공"]["품"] == 0.1 and fp["인력"]["보통인부"]["품"] == 0.05
assert [(m["갈래"], m["시간"]) for m in fp["장비"]] == [(["굴착기"], 0.2)]
assert finger.direct({**hopyo, "줄": hopyo["줄"][2:]}) is None # 노임 없으면 호표 통째 아님