"""표 층마다 열 더하기 · 층 이름 고치기 — `ui_template_sheet_ops.ts` 를 Node 로 바로 돌려 봄. `addLevel` = 고른 열과 그 층 위 머리가 같은 이웃 끝에 `[…위 머리, 새 글, "" …]` · 같은 무리에 같은 글이 있으면 뒤에 수(같은 머리는 가로로 합쳐져 새 열이 안 보였음 — 「분류2 더하기 안 됨」). `setLayerName` = 층 이름(줄 머리 글) · 모자란 층은 빈 글로 채움. """ from __future__ import annotations import json import shutil import subprocess from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] OPS = ROOT / "ui_template" / "sheet" / "ui_template_sheet_ops.ts" pytestmark = pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음") SCRIPT = """ const { addLevel, setLayerName } = await import(process.argv[1]); const base = JSON.parse(process.argv[2]); const out = {}; const heads = (doc) => doc.열.map((c) => [c.id, c.머리]); let doc = structuredClone(base); out.id = addLevel(doc, "a1", 1, 4, "새 분류1"); out.level1 = heads(doc); doc = structuredClone(base); addLevel(doc, "a1", 2, 4, "새 분류2"); addLevel(doc, "a1", 2, 4, "새 분류2"); out.level2 = heads(doc); doc = structuredClone(base); addLevel(doc, "a2", 3, 4, "새 분류3"); out.level3 = heads(doc); doc = structuredClone(base); addLevel(doc, "b1", 2, 4, "L"); out.merged = doc.열.at(-1).머리; doc = structuredClone(base); out.none = addLevel(doc, "zz", 1, 4, "G"); doc = structuredClone(base); setLayerName(doc, 1, " 공법 "); out.layers = doc.층; doc = structuredClone(base); delete doc.층; setLayerName(doc, 2, "분류2"); out.padded = doc.층; console.log(JSON.stringify(out)); """ DOC = { "양식": "시험", "종류": "표", "판": 1, "층": ["종류", "분류1", "분류2", "분류3"], "열": [ {"id": "a1", "머리": ["가", "x", "1", ""], "단위": "m"}, {"id": "a2", "머리": ["가", "x", "2", ""]}, {"id": "a3", "머리": ["가", "y", None, None]}, {"id": "b1", "머리": ["나", None, None, None]}, ], "줄": [], } def _run() -> dict: result = subprocess.run( ["node", "--experimental-strip-types", "--no-warnings", "--input-type=module", "-e", SCRIPT, OPS.as_uri(), json.dumps(DOC, ensure_ascii=False)], capture_output=True, text=True, encoding="utf-8", timeout=60, ) # fmt: skip assert result.returncode == 0, result.stderr return json.loads(result.stdout) def test_level1_goes_to_end_of_same_kind(): got = _run() assert got["id"] == "c1" assert got["level1"] == [ ["a1", ["가", "x", "1", ""]], ["a2", ["가", "x", "2", ""]], ["a3", ["가", "y", None, None]], ["c1", ["가", "새 분류1", "", ""]], ["b1", ["나", None, None, None]], ] def test_level2_twice_gets_distinct_labels(): assert _run()["level2"] == [ ["a1", ["가", "x", "1", ""]], ["a2", ["가", "x", "2", ""]], ["c1", ["가", "x", "새 분류2", ""]], ["c2", ["가", "x", "새 분류2 2", ""]], ["a3", ["가", "y", None, None]], ["b1", ["나", None, None, None]], ] def test_level3_right_after_same_prefix(): assert _run()["level3"][2] == ["c1", ["가", "x", "2", "새 분류3"]] def test_merged_prefix_and_no_column(): got = _run() assert got["merged"] == ["나", None, "L", ""] assert got["none"] is None def test_layer_name(): got = _run() assert got["layers"] == ["종류", "공법", "분류2", "분류3"] assert got["padded"] == ["", "", "분류2"]