"""833-1 지킴 — 원문 표 맨 아래 서술 줄(비고 · [주] · ※) 가르기 · 서술 칸 줄바꿈 판정. 순수 TS(`M01_MasterData/logic/M01_MasterData_logic_source_notes.ts`)를 node 로 돌림 · 서버 · 화면 없음. """ from __future__ import annotations import json import shutil import subprocess import sys from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) pytestmark = pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음") TS = (ROOT / "M01_MasterData/logic/M01_MasterData_logic_source_notes.ts").as_uri() def _node(body: str, data: object = None) -> object: src = f'import {{ noteLine, splitTableNotes, wrapCell }} from "{TS}";\n' + body done = subprocess.run( ["node", "--experimental-strip-types", "--input-type=module", "-e", src], input=json.dumps(data, ensure_ascii=False), capture_output=True, text=True, encoding="utf-8", timeout=120, cwd=ROOT, ) assert done.returncode == 0, done.stderr return json.loads(done.stdout) def test_보기_서술_줄_가르기() -> None: got = _node( r""" const t = [ ["구분", "단위", "수량"], ["보통인부", "인", "1"], ["비고", "- 비계주위 보호망을 시공하지 않는 경우 본 시공량의 8%를 증하여 적용한다.", ""], ["※ 위 표에서 ‘노’는 ‘노지묘’이다.", "", ""], ]; console.log(JSON.stringify([splitTableNotes(t), noteLine(["공종", "Belt폭", ""]), noteLine(["뒷채움 자재비 및 운반비 별산", "", ""]), noteLine(["1", "2", "3"]), noteLine(["단독"]), splitTableNotes([["비고", "긴 글이 머리 줄에 있어도 머리는 몸"]]).notes.length, [wrapCell("7", 3), wrapCell("가".repeat(30), 3), wrapCell("글", 1), wrapCell("짧음\n" + "나".repeat(31), 2)]])); """ ) split = got[0] assert split["rows"] == [["구분", "단위", "수량"], ["보통인부", "인", "1"]] assert [n["label"] for n in split["notes"]] == ["비고", ""] assert split["notes"][1]["text"].startswith("※ 위 표에서") assert got[1:6] == [ None, None, None, None, 0, ] # 짧은 묶음 머리 · 숫자 줄 · 한 칸 · 머리 줄은 서술 아님 assert got[6] == [False, True, True, True] def test_원문_전수_글_그대로_표_밖으로() -> None: """품셈 본문 표 전부 — 줄 수 · 글 합계가 가르기 앞뒤 같음 · 머리 줄은 몸에 남음 · 표 밖 글 표는 200 넘음.""" from M01_MasterData import M01_MasterData_Store as _s # noqa: F401 from M01_MasterData import M01_MasterData_Store_Make as mk tables = [] for book in mk.BOOKS: for _d, _n, _t, folder in mk._chapters(book): for md in sorted(folder.glob("*.md")): for b in mk._blocks(md.read_text(encoding="utf-8").split("\n")): if "table" in b: tables.append(b["table"]) got = _node( r""" const tables = JSON.parse(await new Promise((ok) => { let s = ""; process.stdin.on("data", (d) => (s += d)); process.stdin.on("end", () => ok(s)); })); let lost = 0, moved = 0, headBad = 0; for (const t of tables) { const { rows, notes } = splitTableNotes(t); const had = t.flat().join("").replace(/\s/g, ""); const now = [...rows.flat(), ...notes.flatMap((n) => [n.label, n.text])].join("").replace(/\s/g, ""); if (had !== now || rows.length + notes.length !== t.length) lost++; if (rows.length < 1) headBad++; if (notes.length) moved++; } console.log(JSON.stringify({ n: tables.length, lost, moved, headBad })); """, tables, ) assert got["n"] > 2500 and got["lost"] == 0 and got["headBad"] == 0 assert got["moved"] > 200