"""PLAN 407-4 — 종단 측점 · 구조물 이름표 비켜 그리기(`logic/B06_Section_Label_Tiers.ts`) · 407-5 — B05 종단 아래 표 겹친 칸 세우기(`crowdedThickness` · 두께 = 이웃 사이 틈 − 1). 가까운 측점(1.6 m 등)끼리 이름이 겹치면 위 단 · 안 겹치면 제자리(0) · 이름은 지우지 않음 · 단 수 위 끝(`MAX_LABEL_TIER`) 넘으면 마지막 단 · 글 폭 짐작(한글 = 글자 크기). """ from __future__ import annotations import json import subprocess from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] TS = ROOT / "B06_Section" / "logic" / "B06_Section_Label_Tiers.ts" TYPESCRIPT = ROOT / "config" / "node_modules" / "typescript" SCRIPT = r""" const ts = require(process.argv[1]); const fs = require("fs"); const js = ts.transpileModule(fs.readFileSync(process.argv[2], "utf8"), { compilerOptions: { module: ts.ModuleKind.CommonJS }, }).outputText; const box = { exports: {} }; new Function("exports", "module", js)(box.exports, box); const m = box.exports; const cases = JSON.parse(process.argv[3]); process.stdout.write(JSON.stringify({ max: m.MAX_LABEL_TIER, tiers: cases.map((items) => m.labelTiers(items)), widths: ["19+18 (MC)", "20+0", "배수관"].map((t) => m.labelWidthPx(t, 10)), thick: [ m.crowdedThickness([0, 50, 100], 40, 16), m.crowdedThickness([100, 108, 200], 40, 16), m.crowdedThickness([100, 130, 200], 40, 16), m.crowdedThickness([100, 104, null, 106], 40, 16), m.crowdedThickness([100, null, 103], 40, 16), ], })); """ W = 40.0 # 이름표 폭(px) CASES = [ [{"x": 100, "width": W}, {"x": 200, "width": W}, {"x": 300, "width": W}], # 안 겹침 [{"x": 100, "width": W}, {"x": 108, "width": 24}], # 1.6 m 이웃 — 겹침 [{"x": 108, "width": 24}, {"x": 100, "width": W}], # 차례 뒤바뀜(x 로 셈) [{"x": 100 + i * 2, "width": W} for i in range(6)], # 여섯 겹 — 위 끝 [{"x": 100, "width": W}, {"x": 110, "width": W}, {"x": 150, "width": W}], # 셋째는 제자리 ] @pytest.fixture(scope="module") def r() -> dict: proc = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", "-e", SCRIPT, str(TYPESCRIPT), str(TS), json.dumps(CASES)], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def test_안_겹치면_제자리(r) -> None: assert r["tiers"][0] == [0, 0, 0] def test_겹치면_위_단(r) -> None: assert r["tiers"][1] == [0, 1] assert r["tiers"][2] == [1, 0] # 왼쪽 것이 제자리 def test_위_끝_넘으면_마지막_단(r) -> None: assert r["tiers"][3] == [0, 1, 2, 3, 3, 3] # 이름은 남음(지우지 않음) def test_빈_단은_다시_씀(r) -> None: assert r["tiers"][4] == [0, 1, 0] def test_글_폭(r) -> None: mc, plain, korean = r["widths"] assert mc == pytest.approx(60.0) and plain == pytest.approx(24.0) assert korean == pytest.approx(30.0) def test_표_칸_세우기(r) -> None: no, near, wide, empty, floor = r["thick"] assert no == [None, None, None] # 안 겹침 = 그대로 assert near == [7, 7, None] # 1.6 m 이웃(8 px) = 둘 다 세움 · 두께 7 assert wide == [16, 16, None] # 틈 넓으면 위 끝 16 assert empty == [6, 6, None, 6] # 빈 칸(null) 건너 이웃 · 아래 끝 6 assert floor == [6, None, 6]