Files
Aislo/resources/tester/test_m02_hopyo_match.py
T
eomsangdonandClaude Opus 5.5 9edaec82e3 fix(일위대가실무): 324 다듬기 — 줄 표 줄바꿈 없음 · 고르기 창 [닫기] 안 갈라짐 · 뜻 낱말 안 겹치는 후보 숨김 · 다시 씀 · 새로 덮음 알림 글
- 줄 표: 갈래 · 수량 · 단위 · 엑셀 단가 · 맞춤 · 입력값 · 환산 · 단추 열 줄바꿈 없음(글 폭) · 입력값 길면 줄임표 · 칸 여백 좁힘 · 품명 · 규격 · 대상이 남는 폭
- 고르기 창 머리: [닫기] 단추 줄바꿈 없음 · 안 줄어듦
- 후보: 정리 이름 뜻 낱말(괄호 밖 두 글자 이상 덩어리 · 낱글자 붙임)이 하나도 안 겹치면 뺌(잔토처리 · 임도표지석 → 후보 없음) · 다 걸러지면 「가까운 것 없음」 + [다른 로직 · 자재 찾기]
- 알림: 있던 사전조합 = 「다시 씀 — 빠진 줄 N」 · [새로 만들기] 뒤 = 「새로 만들어 덮음」(토스트 · 판 글)
- 시험 hopyo 넷 42 통과 · typecheck 0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
2026-10-14 22:46:24 +09:00

203 lines
9.9 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.
"""일위대가 실무자료 맞춤(PLAN 324-2 · `M02_Hopyo_Match`) — 규격 → 입력값 · 단위 · 환산 ·
맞춤 차례 · 기억 우선 · 길(보기 · 미리 채움 · 확정) · master_data 원본 그대로. 층은 임시 폴더.
"""
import pytest
from M02_MasterTemplete import M02_Hopyo_Match as hm
from M02_MasterTemplete import M02_Template_Layers as layers
# 올리기 길 시험의 `client` 마당을 같이 씀
# ruff: noqa: F811
from resources.tester.test_m02_hopyo_excel import URL, _post, client, master_hash # noqa: F401
mm = hm.mm
# ── 규격 · 단위 · 환산 ─────────────────────────────────────────────────
def test_규격_이름_붙은_수():
assert hm.numbers("D=1,000mm,일반형") == {"D": (1000, "mm")}
assert hm.numbers("H:1.2m") == {"H": (hm.Decimal("1.2"), "m")}
assert {k: float(v) for k, (v, _) in hm.numbers("B=2.3,H=0.4,야면석").items()} == {
"B": 2.3,
"H": 0.4,
}
assert hm.numbers("L3=35cm적용,장비사용") == {"L3": (35, "cm")}
assert hm.numbers("Φ40×200") == {} and mm.plain_spec("Φ40×200") == "ø40x200"
def test_단위_정규화():
got = [mm.plain_unit(u) for u in ("㎥", "M", "Ton", "TON", "EA", "㎡")]
assert got == ["m3", "m", "톤", "톤", "개", "m2"]
@pytest.mark.parametrize(
("have", "want", "spec", "times", "kind"),
[
("㎥", "㎥", "", 1, "같음"),
("M", "m", "", 1, "같음"),
("kg", "ton", "", 0.001, "단위표"),
("㎡", "㎥", "T=150mm", 0.15, "추정"),
("M", "㎡", "B=2.3,H=0.4", 2.3, "추정"),
("M", "㎥", "B=2.3,T=0.2", 0.46, "추정"),
("개소", "㎥", "", None, "입력"),
("㎥", "㎡ · ㎥", "", 1, "두 단위"),
("M", "㎡ · ㎥", "", None, "입력"),
],
)
def test_환산(have, want, spec, times, kind):
assert hm.factor(have, want, spec) == {"배": times, "갈래": kind}
SPECS = [
{"이름": "뒷길이", "단위": "㎝", "고르기": [25, 35, 45], "자동값": None},
{"이름": "관경", "단위": "mm", "자동값": None},
{"이름": "설치높이", "단위": "m", "자동값": None},
{
"이름": "기계",
"고르기": ["0201-0020", "0201-0060"],
"고르기이름": {
"0201-0020": "굴착기(무한궤도) 0.2㎥",
"0201-0060": "굴착기(무한궤도) 0.6㎥",
},
"자동값": None,
},
{"이름": "횟수", "고르기": ["3회사용시", "4회사용시"], "자동값": None},
{"이름": "단위당", "고르기": ["㎡당", "㎥당"], "자동값": None},
{"이름": "지역", "고르기": ["전국평균", "서울"], "자동값": "전국평균"},
{"이름": "보정작업", "고르기": ["해당 없음", "전석섞인토사"], "자동값": None},
]
def test_규격에서_입력값():
line = {"이름": "찰붙임(4회)", "규격": "L3=35cm적용,굴삭기0.6㎥,D=1,000mm,H:1.2m", "단위": "㎥"}
values, unread = hm.spec_inputs(line, SPECS)
assert values == {
"뒷길이": 35,
"관경": 1000,
"설치높이": 1.2,
"기계": "0201-0060",
"횟수": "4회사용시",
"단위당": "㎥당",
}
assert unread == ["보정작업"] # 지역 = 자동값 · 못 읽은 것만 표시
other = {"이름": "찰붙임", "규격": "L3=40cm", "단위": "㎡"}
values, unread = hm.spec_inputs(other, SPECS[:1])
assert values == {} and unread == ["뒷길이"] # 고르기 밖 수 = 빈 값 + 표시
# ── 맞춤 차례 ────────────────────────────────────────────────────────
def _hopyo(client, no, layer="personal"):
res = client.get(f"{URL.format(layer)}/HP-000001/{no}")
assert res.status_code == 200, res.text
return {one["이름"]: one["맞춤"] for one in res.json()["호표"]["줄"]}
def test_이름_같음_후보_호표_퍼센트(client):
before = master_hash()
assert _post(client).status_code == 200
first = _hopyo(client, 1)
plywood = first["합판거푸집"]
assert plywood["상태"] == "같음" and plywood["대상"]["로직"] == "GF000160"
assert plywood["입력값"] == {"횟수": "4회사용시"} and plywood["들어감"] is True
remicon = first["레미콘(25-21-120)"]
assert remicon["상태"] == "후보" and remicon["들어감"] is False
assert all(c["규격"] == "25-21-120" for c in remicon["후보"][:3]) # 규격 같은 자재 먼저
dig = _hopyo(client, 3)["구조물터파기(인력100%)"]
assert dig["상태"] == "후보" and len(dig["후보"]) == 5
assert dig["후보"][0]["이름"].startswith("구조물터파기")
ref = _hopyo(client, 45)["고화매트재료비"]
assert ref["상태"] == "호표" and ref["대상"] == {"호표": 46, "단위": "㎡"} and ref["들어감"]
pct = _hopyo(client, 46)["잡재료비"]
assert pct["상태"] == "%" and pct["들어감"] is False
whole = client.get(f"{URL.format('personal')}/HP-000001").json()
assert whole["맞춤"][1] == 415 and 0 < whole["맞춤"][0] < 415
assert next(h for h in whole["호표"] if h["번"] == 61)["맞춤"] == [0, 0]
assert master_hash() == before
def test_미리_채움_확정_기억_우선(client):
assert _post(client).status_code == 200
url = f"{URL.format('personal')}/HP-000001/3/guess"
got = client.post(url, json={"차례": 1, "대상": {"로직": "GF000101"}}).json()
assert got["환산"] == {"배": 1, "갈래": "같음"} and got["대상"]["단위"] == "㎥"
assert client.post(url, json={"차례": 1, "대상": {"로직": "XX"}}).status_code == 400
key = _hopyo(client, 3)["구조물터파기(인력100%)"]["열쇠"]
assert key == "구조물터파기(인력100%)|토사|m3"
body = {"줄": {key: {"로직": "GF000101", "입력값": {"지역": "서울"}, "환산": 1}}}
assert client.post("/api/m02/layers/personal/hopyo-memory", json=body).status_code == 200
dig = _hopyo(client, 3)["구조물터파기(인력100%)"]
assert (dig["상태"], dig["대상"]["로직"], dig["입력값"], dig["들어감"]) == (
"기억",
"GF000101",
{"지역": "서울"},
True,
)
# 이름 같음보다 기억이 앞섬 · 빼기
plywood = _hopyo(client, 1)["합판거푸집"]["열쇠"]
out = {"줄": {plywood: {"빼기": True}}}
assert client.post("/api/m02/layers/personal/hopyo-memory", json=out).status_code == 200
assert _hopyo(client, 1)["합판거푸집"]["상태"] == "빼기"
clear = {"줄": {plywood: None}}
assert client.post("/api/m02/layers/personal/hopyo-memory", json=clear).status_code == 200
assert _hopyo(client, 1)["합판거푸집"]["상태"] == "같음"
def test_확정_검사와_위_층_기억(client):
bad = [
{"로직": "GC000422", "환산": 1}, # 돈 아닌 로직
{"로직": "GF000101", "환산": 0},
{"로직": "GF000101", "자재": "MT004258", "환산": 1},
{"환산": 1},
]
for one in bad:
res = client.post("/api/m02/layers/personal/hopyo-memory", json={"줄": {"a|b|c": one}})
assert res.status_code == 400, one
assert client.post("/api/m02/layers/system/hopyo-memory", json={"줄": {}}).status_code == 403
client.who.update(role="SYSTEM_ADMIN")
key = "구조물터파기(인력100%)|토사|m3"
body = {"줄": {key: {"로직": "GF000103", "환산": 1}}}
assert client.post("/api/m02/layers/system/hopyo-memory", json=body).status_code == 200
client.who.update(role="USER")
assert _post(client).status_code == 200
assert _hopyo(client, 3)["구조물터파기(인력100%)"]["대상"]["로직"] == "GF000103" # 위 층
mine = {"줄": {key: {"로직": "GF000101", "환산": 1}}}
assert client.post("/api/m02/layers/personal/hopyo-memory", json=mine).status_code == 200
assert _hopyo(client, 3)["구조물터파기(인력100%)"]["대상"]["로직"] == "GF000101" # 같은 층 먼저
assert hm.chain(layers.personal_dir(7, 42))[1] == layers.company_dir(7)
def test_로직_추가_고르기_줄은_이_층과_위_층(client):
client.who.update(role="SYSTEM_ADMIN")
assert _post(client, "system").status_code == 200
client.who.update(role="USER")
assert _post(client).status_code == 200
rows = client.get("/api/m02/layers/personal/hopyo-picks").json()["줄"]
assert [r["층"] for r in rows].count("personal") == 68
assert [r["층"] for r in rows].count("system") == 68
three = next(r for r in rows if r["층"] == "system" and r["번"] == 3)
assert {k: three[k] for k in ("주인", "키", "이름", "단위")} == {
"주인": None,
"키": "HP-000001",
"이름": "임도표지석",
"단위": "개소",
}
assert three["맞춤"][1] == 4
system = client.get("/api/m02/layers/system/hopyo-picks").json()["줄"]
assert {r["층"] for r in system} == {"system"} # 마스터 = 마스터만
def test_뜻_낱말이_안_겹치면_후보_아님():
assert hm.words("면 목") == {"면목"} and hm.words("구조물되메우기(인력100%)") == {
"구조물되메우기"
}
assert hm.words("되메우기 및 다짐(소형장비)") == {"되메우기", "다짐"}
soil = {"이름": "잔토처리(인력100%)", "규격": "", "단위": "㎥", "갈래": "단가산출"}
assert hm.candidates(soil, "로직") == [] # 「처리」 두 글자만 겹침(소금처리 · 바탕처리)
stone = {"이름": "임도표지석(받침,글새김포함)", "규격": "", "단위": "㎥", "갈래": "자재"}
assert hm.candidates(stone, "자재") == [] # 속도표지판 · 도로표지용페인트
got = hm.match_line(soil, [], {})
assert got["상태"] == "없음" and got["후보"] == []
fill = {"이름": "구조물되메우기(인력100%)", "규격": "", "단위": "㎥", "갈래": "단가산출"}
assert hm.candidates(fill, "로직")[0]["이름"] == "되메우기" # 한쪽 낱말에 듦 = 겹침