Files
Aislo/resources/tester/test_m01_pick.py
T
eomsangdonandClaude Sonnet 5 af842c0337 feat(M01): 재료 기본 검색어 찾기 · 고름 받기 · 단위 환산 · 단위 경고 (PLAN 8-2)
- 새 master_pick.py — 검색어 찾기(지역 낱말은 차례만) · 고름(호표 줄 차례 → 자재 키) · 같은 성격 단위 환산 · 단위경고 칸 · 기계 목록 밖 원문 분류번호 받기
- Router 몸에 고름 칸 · check_master 검색어 후보 0 · 단위 경고
- 검색어 없는 줄은 옛 길 그대로 — 1,354 자동값 금액 변화 0
- 시험 test_m01_pick 8개

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
2026-09-24 20:24:43 +09:00

115 lines
4.8 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.
"""M01 재료 기본 검색어 · 고름 · 단위 환산 · 단위 경고 — PLAN 8-1 · 8-2 계약.
검색어 든 견본 로직 줄을 시험 안에서 만들어(`POST /calc` 의 `row` — 저장 안 함) 돌림. 정본 폴더는 읽기만.
"""
from __future__ import annotations
from decimal import Decimal
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from M01_MasterData import M01_MasterData_Router as router_module
from M01_MasterData import M01_MasterData_Store as store
mf = store.cm.mf
mp = mf.mp
@pytest.fixture(scope="module")
def client() -> TestClient:
app = FastAPI()
app.include_router(router_module.router)
return TestClient(app)
def _sample(term: str, unit: str, **cond) -> dict:
"""재료 줄 하나짜리 견본 로직 — 검색어 줄 하나 · 수량 1."""
return {
"이름": "검색어 견본",
"구분": "자체",
"입력": [],
"호표": [
{
"종류": "재료",
"요소": {"검색어": term, **cond},
"이름": "견본 재료",
"단위": unit,
"수량": "1",
"비목": "재료비",
}
],
}
def _line(client: TestClient, row: dict, picks: dict | None = None, path: str = "calc") -> dict:
body = {"key": "GF999999", "inputs": {}, "row": row, **({"고름": picks} if picks else {})}
got = client.post(f"/api/m01/{path}", json=body).json()
assert got.get("ok", True) is True, got
return got["lines"][0] if path == "calc" else got
def test_검색어로_찾고_지역_낱말이_맞는_줄이_먼저(client) -> None:
seoul = _line(client, _sample("합판(내수) 12t 서울", "㎡"))
assert seoul["출처"].startswith("MT000018") and seoul["단가"] == 11354 # 값 열 가운데 낮은 값
busan = _line(client, _sample("합판(내수) 12t 부산", "㎡"))
assert busan["출처"].startswith("MT000020") and busan["단가"] == 11488
assert "단위경고" not in seoul
def test_고름은_그_줄만_그_품목으로_셈(client) -> None:
row = _sample("합판(내수) 12t 서울", "㎡")
got = _line(client, row, {"0": "MT000019"})
assert got["출처"].startswith("MT000019") and got["단가"] == 11556
assert _line(client, row)["단가"] == 11354 # 요청마다 — 저장 안 함
text = _line(client, row, {"0": "MT000019"}, "text")
assert text["ok"] is True # 읽는 식도 같은 몸으로 돎
def test_같은_성격_단위는_줄_단위로_환산(client) -> None:
got = _line(client, _sample("어닐링철선 서울 4.0mm", "톤")) # 자재 kg → 줄 톤
assert got["단가"] == 1610000 and "단위경고" not in got
got = _line(client, _sample("어닐링철선 서울 4.0mm", "g"))
assert got["단가"] == pytest.approx(1.61)
def test_성격이_다르면_계산은_하고_단위경고(client) -> None:
got = _line(client, _sample("어닐링철선 서울 4.0mm", "m"))
assert got["단가"] == 1610 and got["단위경고"] == "줄 m · 자재 kg"
assert got["금액"] == 1610
def test_검색어_후보가_없으면_그_줄만_비움(client) -> None:
got = client.post(
"/api/m01/calc", json={"key": "GF999999", "inputs": {}, "row": _sample("없는물건zzz", "개")}
).json()
assert got["ok"] is True and got["lines"][0]["금액"] is None
assert "후보 없음" in got["lines"][0]["까닭"]
def test_기계_입력은_목록_밖_원문번호도_받음(client) -> None:
key = "GC000267"
inputs = {**store.auto(key)["값"], "기계": "0101-0007"} # 고르기 목록 밖 · 기계 마스터엔 있음
got = client.post("/api/m01/calc", json={"key": key, "inputs": inputs}).json()
assert got["ok"] is True, got
bad = client.post("/api/m01/calc", json={"key": key, "inputs": {**inputs, "기계": "9999-9999"}})
assert bad.json()["ok"] is False # 기계 마스터에 없는 번호는 그대로 막힘
def test_단위_환산_표() -> None:
assert mp.convert(Decimal(1610), "kg", "톤") == 1610000
assert mp.convert(Decimal(5), "Ton", "kg") == Decimal("0.005")
assert mp.convert(Decimal(100), "㎡", "㎠") == Decimal("0.01")
assert mp.convert(Decimal(7), "kg", "m") == 7 # 성격이 다르면 그대로
assert mp.same_kind("ℓ", "㎥") and not mp.same_kind("kg", "m")
def test_check_master_검색어_후보0_단위경고(client) -> None:
whole = store.loaded()[1]
assert mf.check_pick(whole, "줄", {"검색어": "합판(내수) 12t 서울"}) == []
assert "후보 0" in mf.check_pick(whole, "줄", {"검색어": "없는물건zzz"})[0]
assert mf.check_unit(whole, "줄", {"검색어": "어닐링철선 서울 4.0mm"}, "kg") == []
assert "성격이 다름" in mf.check_unit(whole, "줄", {"검색어": "어닐링철선 서울 4.0mm"}, "m")[0]