- 산림 차례(PDF 3~12쪽)에서 장 14 · 절 189 · 쪽 범위 · 시작/끝 표지 - 절 머리는 번호로 찾음 — 차례 이름 오타 다섯(면벅·조림·우드그래풀·소형 운재) 때문 - 표지는 PDF 글자 그대로(번호 뒤 마침표 포함) · 띄어쓰기만 차례를 따름 - 다른 창 브랜치에 이미 있는 파일은 안 만듦(합칠 때 부딪힘 막음) - 시험 test_pum_md_tool.py: 순수 함수 · 산림 차례 개수 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
86 lines
3.6 KiB
Python
86 lines
3.6 KiB
Python
"""품셈 PDF → 절별 md 도구(`_pipeline/pum_md_tool.py`) — 순수 함수 · 산림 차례 개수.
|
|
|
|
규칙: `resources/knowledge/original/원가계산/_품셈md_작성규칙.md`.
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(ROOT / "resources/knowledge/original/_pipeline"))
|
|
|
|
import pum_md_tool as tool # noqa: E402
|
|
|
|
|
|
def test_parse_toc_strips_leaders_and_reads_appendix():
|
|
lines = ["제1장", "적용기준 ·········", "1", "1-1", "일반사항 ·····", "1", "부록 ······", "204"]
|
|
got = tool.parse_toc(lines)
|
|
assert [(e.ident, e.name, e.page) for e in got] == [
|
|
("제1장", "적용기준", 1),
|
|
("1-1", "일반사항", 1),
|
|
("부록", "", 204),
|
|
]
|
|
with pytest.raises(ValueError):
|
|
tool.parse_toc(["엉뚱한 줄", "1"])
|
|
|
|
|
|
def test_key_ignores_spaces_dot_after_number_and_middle_dots():
|
|
assert tool.key("9-5. 발파암") == tool.key("9-5 발파암")
|
|
assert tool.key("[부록1]할인") == tool.key("부록1 할인")
|
|
assert tool.key("보수·복구") == tool.key("보수․복구")
|
|
|
|
|
|
def test_heading_pattern_by_number_only():
|
|
sec = tool.heading_pattern("7-1")
|
|
assert sec.match("7-1. 벌도")
|
|
assert not sec.match("7-11. 동력상하차기") # 번호가 앞머리만 같음
|
|
assert not sec.match("7-1-1. 항")
|
|
assert tool.heading_pattern("제1장").match("제1장적용기준")
|
|
assert not tool.heading_pattern("제1장").match("제10장자재")
|
|
assert tool.heading_pattern("부록1").match("[부록1]할인")
|
|
assert not tool.heading_pattern("부록1").match("[부록10]x")
|
|
|
|
|
|
def test_respace_takes_toc_spacing_but_body_glyphs():
|
|
toc = "임산물 운반로 신설 및 보수․복구"
|
|
assert tool.respace("임산물운반로신설및보수·복구", toc) == "임산물 운반로 신설 및 보수·복구"
|
|
# 차례 오타(조림 ≠ 조립) — 본문 그대로
|
|
assert tool.respace("철근현장가공및조립", "철근 현장가공 및 조림") == "철근현장가공및조립"
|
|
|
|
|
|
def test_heading_text_keeps_number_dot():
|
|
entry = tool.Entry("4-5", "벌도 위험목 점검", 51)
|
|
assert tool.heading_text(entry, "4-5. 벌도위험목점검") == "4-5. 벌도 위험목 점검"
|
|
assert tool.section_name(entry, "4-5. 벌도위험목점검") == "벌도 위험목 점검"
|
|
chapter = tool.Entry("제2장", "소요재료 및 기계손료", 28)
|
|
assert tool.heading_text(chapter, "제2장소요재료및기계손료") == "제2장 소요재료 및 기계손료"
|
|
|
|
|
|
def test_section_file_name():
|
|
chapter = tool.Entry("제10장", "자재․장비 운반", 143)
|
|
section = tool.Entry("10-5", "목재 운반/적재", 150)
|
|
got = tool.section_file(Path("본문"), chapter, section)
|
|
assert got.as_posix() == "본문/제10장_자재․장비_운반/10-05_목재_운반적재.md"
|
|
|
|
|
|
def test_head_round_trip(tmp_path):
|
|
path = tmp_path / "a.md"
|
|
path.write_text(
|
|
tool.head_text({"절": "9-5. 발파암", "상태": "대기"}) + "\n본문\n", encoding="utf-8"
|
|
)
|
|
head = tool.read_head(path)
|
|
assert list(head) == list(tool.HEAD_KEYS)
|
|
assert head["절"] == "9-5. 발파암" and head["상태"] == "대기" and head["작성"] == ""
|
|
|
|
|
|
def test_forest_toc_counts():
|
|
"""산림 차례 — 14장 · 189절(PDF 3~12쪽)."""
|
|
pymupdf = pytest.importorskip("pymupdf")
|
|
book = tool.BOOKS["산림"]
|
|
with pymupdf.open(book["pdf"]) as doc:
|
|
entries = tool.toc_entries(doc, *book["toc"])
|
|
assert sum(e.ident.startswith("제") for e in entries) == 14
|
|
assert sum(e.ident.count("-") == 1 for e in entries) == 189
|