Files
Aislo/resources/tester/test_m01_logic_source.py
T

157 lines
6.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.
"""M01 로직 원문 — 출처 글 → 품셈 본문 절(44-4). 원본은 읽기만."""
from __future__ import annotations
import json
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
from M01_MasterData import M01_MasterData_Store_Make as make
def test_build_civil_section_with_table() -> None:
got = make.source("건설품셈 토목 1-1-2")
assert len(got["found"]) == 1
one = got["found"][0]
assert one["matched"] == "1-1-2"
assert one["file"].startswith("원가계산/건설공사_표준품셈/본문/02_토목부문/제01장_")
assert one["blocks"][0]["h"] == 3 and one["blocks"][0]["text"].startswith("1-1-2 유도선")
table = next(b["table"] for b in one["blocks"] if "table" in b)
assert table[0][0] == "구분" and ["특별인부", "인", "2", "1,350", "1,560"] in table
# 다음 절(1-1-3 …) 앞에서 끊김 · 주석 줄 뺌
assert not any("1-1-3" in b.get("text", "") for b in one["blocks"])
assert not any(b.get("p", "").startswith("<!--") for b in one["blocks"])
def test_forest_and_many_numbers() -> None:
forest = make.source("산림품셈 3-4-2 1")["found"]
assert [x["matched"] for x in forest] == ["3-4-2"]
many = make.source("건설품셈 공통 8-1-5 · 8-1-6")["found"]
assert [x["number"] for x in many] == ["8-1-5", "8-1-6"]
def test_no_link() -> None:
assert make.source("현장 자체 단가")["found"] == []
assert make.source("건설품셈 토목 99-9-9")["found"] == []
def test_most_master_logics_link() -> None:
"""정본 로직 출처 대부분이 원문 절에 닿음."""
hit = total = 0
for path in store.FOLDER.glob("로직_*품셈_*.json"):
for row in json.loads(path.read_text(encoding="utf-8"))["줄"]:
total += 1
hit += bool(make.source(row.get("출처", ""))["found"])
assert total > 1000 and hit / total > 0.9, (hit, total)
def test_route() -> None:
app = FastAPI()
app.include_router(router_module.router)
got = TestClient(app).get("/api/m01/logic/source", params={"src": "산림품셈 3-1"}).json()
assert got["found"][0]["matched"] == "3-1"
def test_tables_split_and_br() -> None:
"""빈 줄 · 주석이 붙은 표 둘을 가름(49-2) · 칸 안 `<br>` = 줄바꿈."""
one = make.source("건설품셈 공통 6-1-1")["found"][0]
tables = [b["table"] for b in one["blocks"] if "table" in b]
assert [len(t[0]) for t in tables] == [7, 2]
assert tables[0][2][0] == "인력운반\n타설"
def test_markdown_stripped() -> None:
"""역슬래시 · 인용 `>` 머리 · 글 안 주석을 벗김(50-2) — 모든 정본 출처 원문에 0."""
bad = 0
for path in store.FOLDER.glob("로직_*품셈_*.json"):
for row in json.loads(path.read_text(encoding="utf-8"))["줄"]:
for one in make.source(row.get("출처", ""))["found"]:
for b in one["blocks"]:
t = b.get("p") or b.get("text") or ""
bad += "\\" in t or "<!--" in t or t.startswith(">")
assert bad == 0
one = make.source("산림품셈 3-4-2 1")["found"][0]
assert any(b.get("p") == "Q = 3,600 × q × K × f × E / Cm" for b in one["blocks"])
def test_item_marked() -> None:
"""출처 항 · 주 번호 → 그 조각만 hit(절은 통째) · 못 찾으면 item 없음."""
def hits(src: str) -> list[str]:
one = make.source(src)["found"][0]
return [(b.get("p") or b.get("text") or "table")[:2] for b in one["blocks"] if b.get("hit")]
one = make.source("산림품셈 3-4-2 1")["found"][0]
assert one["item"] == "1" and one["blocks"][0].get("hit") is None
assert not any(b.get("hit") for b in one["blocks"] if b.get("p", "").startswith("2."))
assert hits("산림품셈 3-4-2 1")[0] == "1."
assert hits("산림품셈 9-7-1 주⑥") == ["⑥ "]
assert make.source("산림품셈 13-10-2 2")["found"][0]["item"] == "2"
assert "item" not in make.source("산림품셈 3-4-2")["found"][0]
def test_item_all_marked() -> None:
"""항 · 주 번호가 달린 정본 출처는 전부 표시가 붙음(전수)."""
total = missing = 0
for path in store.FOLDER.glob("로직_*품셈_*.json"):
for row in json.loads(path.read_text(encoding="utf-8"))["줄"]:
src = row.get("출처", "")
if not any(i for _n, i in make._NUMBER.findall(src)):
continue
total += 1
missing += not any(f.get("item") for f in make.source(src)["found"])
assert total >= 30 and missing == 0, (total, missing)
def _m02_client(role: str = "USER") -> TestClient:
from common_util.common_util_auth import verify_session
from M02_MasterTemplete import M02_MasterTemplete_Router_Combos as combos
app = FastAPI()
app.include_router(combos.router)
app.dependency_overrides[verify_session] = lambda: {"user_id": 42, "role": role}
return TestClient(app)
def test_m02_원문_대리_길과_pdf() -> None:
"""85-4 — 일반 사용자도 원문(M01 길과 같은 몸) · pdf 통째(책 이름만 · 그 밖 400 · 한글 파일명)."""
from M02_MasterTemplete import M02_MasterTemplete_Router_Combos as combos
client = _m02_client()
got = client.get("/api/m02/logic-lib/source", params={"src": "산림품셈 3-1"})
assert got.status_code == 200 and got.json() == make.source("산림품셈 3-1")
for book in ("건설", "산림"):
res = client.get("/api/m02/logic-lib/source-pdf", params={"book": book})
assert res.status_code == 200 and res.headers["content-type"] == "application/pdf"
assert (
len(res.content) == combos.SOURCE_PDF[book].stat().st_size
and res.content[:4] == b"%PDF"
)
assert "filename*=utf-8''" in res.headers["content-disposition"]
again = client.get(
"/api/m02/logic-lib/source-pdf",
params={"book": book},
headers={"if-none-match": res.headers["etag"]},
)
assert again.status_code == 304
for bad in ("../../main.py", "건설품셈", ""):
assert client.get("/api/m02/logic-lib/source-pdf", params={"book": bad}).status_code == 400
def test_원문_패널_길_주입() -> None:
"""85-4 — M01 은 옛 길 그대로(기본값) · M02 일위대가 상세는 M02 길 + pdf."""
from pathlib import Path
root = Path(__file__).resolve().parents[2]
src = (root / "M01_MasterData/M01_MasterData_UI_LogicLab_Source.ts").read_text(encoding="utf-8")
assert 'opts.path ?? "/m01/logic/source"' in src
side = (root / "M01_MasterData/M01_MasterData_UI_LogicLab_Side.ts").read_text(encoding="utf-8")
assert "createSourceView()" in side
labor = (root / "M02_MasterTemplete/M02_MasterTemplete_Labor_Detail.ts").read_text(
encoding="utf-8"
)
assert 'path: "/m02/logic-lib/source"' in labor and 'pdf: "/m02/logic-lib/source-pdf"' in labor