- 서버 원문 조각에서 역슬래시 · 인용 머리 · 글 안 주석 벗김(원본 자료 손 안 댐) - 출처 항 · 주 번호(3-4-2 1 · 9-7-1 주⑥)를 source() 답에 실음 — 그 조각 hit 표시 - 패널이 그 항을 옅은 바탕 + 막대로 강조 · 보이게 스크롤 · 머리에 「1항」 · 「주⑥」 - 시험 3 추가 · 화면 시나리오 50-2 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPJGtfXo6GMbcpiboQC4uK
107 lines
4.6 KiB
Python
107 lines
4.6 KiB
Python
"""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)
|